这里提供一个c++11实现函数闭包和多线程执行类的例子,主要包含如下特性:
可作为学习c++模板的素材,因为实在简单,因而也没有比较解释了
/**
* @brief Simple thread runner based on function closure and variadic parameters
* packing.
* @author zpfeng
* @copyright (C) 2019-2020 zpfeng
* @license BSD 3-CLAUSE
*/
#ifndef __SIMPLE_THREADING_H__
#define __SIMPLE_THREADING_H__
#include
#include
#include
#include
#include
#include
#include
namespace simple_threading {
template using Invoke = typename T::type;
template struct IdxSeq { using type = IdxSeq; };
template struct Concat;
template
struct Concat, IdxSeq> : IdxSeq {};
template
struct GenSeq : Invoke>, Invoke>>> {};
template <> struct GenSeq<0> : IdxSeq<> {};
template <> struct GenSeq<1> : IdxSeq<0> {};
template using IdxSeqFor = GenSeq;
template
constexpr void CallThreadFunc(Callable &&f, Tuple &&t, IdxSeq) {
f(std::get(std::forward(t))...);
}
template
constexpr void ApplyThreadFunc(Callable &&f, Tuple &&t) {
CallThreadFunc(
std::forward(f), std::forward(t),
GenSeq::type>::value>());
}
template struct Functor {
Functor(Ret (*func)(Params...))
: _func(func) {}
Ret operator()(const Params &... param) const { return _func(param...); }
Ret (*_func)(Params...);
};
template struct ClassFunctor {
ClassFunctor(Ret (Class::*func)(Params...), Class &obj)
: _func(func)
, _obj(obj) {}
Ret operator()(const Params &... param) const { return (_obj.*_func)(param...); }
Ret (Class::*_func)(Params...);
Class &_obj;
};
template struct ClassConstFunctor {
ClassConstFunctor(Ret (Class::*func)(Params...) const, const Class &obj)
: _func(func)
, _obj(obj) {}
Ret operator()(const Params &... param) const { return (_obj.*_func)(param...); }
Ret (Class::*_func)(Params...) const;
const Class &_obj;
};
template
std::function ThreadFunc(Ret (*func)(Params...), Params2 &&... param) {
auto f = Functor(func);
return [f, tp = std::make_tuple(std::forward(param)...)] {
ApplyThreadFunc(f, tp);
};
}
template
std::function ThreadFunc(Ret (Class::*func)(Params...), Class &obj,
Params2 &&... param) {
auto f = ClassFunctor(func, obj);
return [f, tp = std::make_tuple(std::forward(param)...)] {
ApplyThreadFunc(f, tp);
};
}
template
std::function ThreadFunc(Ret (Class::*func)(Params...) const, const Class &obj,
Params2 &&... param) {
auto f = ClassConstFunctor(func, obj);
return [f, tp = std::make_tuple(std::forward(param)...)] {
ApplyThreadFunc(f, tp);
};
}
template
std::shared_ptr MakeShared(Params &&... param) {
return std::shared_ptr(new D(std::forward(param)...));
}
struct ThreadFunctorBase {
ThreadFunctorBase(int priority)
: _priority(priority) {}
virtual ~ThreadFunctorBase() noexcept = default;
virtual void operator()() const = 0;
int _priority;
struct LessThan {
bool operator()(const std::shared_ptr &lhs,
const std::shared_ptr &rhs) const {
return lhs->_priority < rhs->_priority;
}
};
};
template struct ThreadFunctorImpl : ThreadFunctorBase {
ThreadFunctorImpl(Callable f, int priority = 0)
: ThreadFunctorBase(priority)
, _f(std::move(f)) {}
void operator()() const override { _f(); }
Callable _f;
};
class SimpleTaskQueue {
public:
using task_type = std::shared_ptr;
SimpleTaskQueue() = default;
virtual ~SimpleTaskQueue() = default;
void Push(task_type &&t) { _q.push(std::forward(t)); }
bool Pop(task_type &t) {
std::lock_guard lg(_lock);
if (_q.empty())
return false;
else {
t = _q.top();
_q.pop();
return true;
}
}
private:
std::mutex _lock;
std::priority_queue, ThreadFunctorBase::LessThan>
_q;
};
class SimpleThreadRunner {
public:
SimpleThreadRunner(int run_thread)
: _thread_cnt(run_thread) {}
~SimpleThreadRunner() = default;
template void AddTask(Callable &&f, int priority = 0) {
_q.Push(MakeShared>(f, priority));
}
void Start() {
for (int i = 0; i < _thread_cnt; ++i) {
std::thread t([this]() {
SimpleTaskQueue::task_type f_ptr = nullptr;
while (this->_q.Pop(f_ptr)) {
(*f_ptr)();
}
});
_t.push_back(std::move(t));
}
}
void Join() {
for (auto &t : _t) {
t.join();
}
_t.clear();
}
private:
int _thread_cnt = 0;
SimpleTaskQueue _q;
std::vector _t;
};
} // namespace simple_threading
#endif
示例:
#include "threading.h"
#include
using namespace std;
using namespace simple_threading;
class ABC {
public:
void heavy_method(size_t times, int job_id) {
// cout << times << endl;
size_t val = 0;
for (size_t i = 0; i < times; ++i) {
val += i * i * i;
}
cout << std::this_thread::get_id() << ": finish jobs" << job_id << " and val is:" << val << endl;
}
};
size_t test_method(size_t times, int job_id) {
size_t val = 0;
for (size_t i = 0; i < times; ++i) {
val += i * i * i;
}
cout << std::this_thread::get_id() << ": finish jobs" << job_id << " and val is:" << val << endl;
return val;
}
int main() {
SimpleThreadRunner sr(2);
ABC abc;
sr.AddTask(ThreadFunc(&test_method, 101233532, 9), 1);
sr.AddTask(ThreadFunc(&test_method, 101232212, 10), 1);
sr.AddTask(ThreadFunc(&test_method, 101235512, 11), 1);
sr.AddTask(ThreadFunc(&test_method, 101236612, 12), 1);
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 100000000, 1));
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 104000000, 2), 10);
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 110000000, 3), 8);
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 100300000, 4));
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 100000010, 5));
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 101000000, 6), 10);
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 110000000, 7), 8);
sr.AddTask(ThreadFunc(&ABC::heavy_method, abc, 100100000, 8));
sr.Start();
sr.Join();
cout << "end" << endl;
return 0;
}