I want to create a thread pool for experimental purposes (and for the fun factor). It should be able to process a wide variety of tasks (so I can possibly use it in later projec
So the hard part is that packaged_task is move-only, otherwise you could just toss it into a std::function, and run those in your threads.
There are a few ways around this.
First, ridiculously, use a packaged_task to store a packaged_task. I'd advise against this, but it does work. ;) (what is the signature of operator() on packaged_task? What is the required signature for the objects you pass to packaged_task?)
Second, wrap your packaged_task in a shared_ptr, capture that in a lambda with signature void(), store that in a std::function, and done. This has overhead costs, but probably less than the first solution.
Finally, write your own move-only function wrapper. For the signature void() it is short:
struct task {
template,
class=decltype( std::declval()() )
>
task( F&& f ):
ptr(
new dF(std::forward(f)),
[](void* ptr){ delete static_cast(ptr); }
),
invoke([](void*ptr){
(*static_cast(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(ptr);}
private:
std::unique_ptr ptr;
void(*invoke)(void*) = nullptr;
};
and simple. The above can store packaged_task for any type R, and invoke them later.
This has relatively minimal overhead -- it should be cheaper than std::function, at least the implementations I've seen -- except it does not do SBO (small buffer optimization) where it stores small function objects internally instead of on the heap.
You can improve the unique_ptr<> ptr container with a small buffer optimization if you want.