c++ - Implementing a simple, generic thread pool in C++11 -
i want create thread pool experimental purposes (and fun factor). should able process wide variety of tasks (so can possibly use in later projects).
in thread pool class i'm going need sort of task queue. since standard library provides std::packaged_task
since c++11 standard, queue std::deque<std::packaged_task<?()> > task_queue
, client can push std::packaged_task
s queue via sort of public interface function (and 1 of threads in pool notified condition variable execute it, etc.).
my question related template argument of std::packaged_task<?()>
s in deque.
the function signature ?()
should able deal type/number of parameters, because client can like:
std::packaged_task<int()> t(std::bind(factorial, 342)); thread_pool.add_task(t);
so don't have deal type/number of parameters.
but what should return value be? (hence question mark)
if make whole thread pool class template class, 1 instance of able deal tasks specific signature (like
std::packaged_task<int()>
).i want 1 thread pool object able deal kind of task.
if go
std::packaged_task<void()>
, function invoked returns integer, or @ all, thats undefined behaviour.
so hard part packaged_task<r()>
move-only, otherwise toss std::function<void()>
, , run in threads.
there few ways around this.
first, ridiculously, use packaged_task<void()>
store packaged_task<r()>
. i'd advise against this, work. ;) (what signature of operator()
on packaged_task<r()>
? required signature objects pass packaged_task<void()>
?)
second, wrap packaged_task<r()>
in shared_ptr
, capture in lambda signature void()
, store in std::function<void()>
, , done. has overhead costs, less first solution.
finally, write own move-only function wrapper. signature void()
short:
struct task { template<class f, class df=std::decay_t<f>, class=decltype( std::declval<df&>()() ) > task( f&& f ): ptr( new df(std::forward<f>(f)), [](void* ptr){ delete static_cast<df*>(ptr); } ), invoke([](void*ptr){ (*static_cast<df*>(ptr))(); }) {} void operator()()const{ invoke( ptr.get() ); } task(task&&)=default; task&operator=(task&&)=default; task()=default; ~task()=default; explicit operator bool()const{return static_cast<bool>(ptr);} private: std::unique_ptr<void, void(*)(void*)> ptr; void(*invoke)(void*) = nullptr; };
and simple. above can store packaged_task<r()>
type r
, , invoke them later.
this has relatively minimal overhead -- should cheaper std::function
, @ least implementations i've seen -- except not sbo (small buffer optimization) stores small function objects internally instead of on heap.
you can improve unique_ptr<> ptr
container small buffer optimization if want.
Comments
Post a Comment