My question is from this implementation of a ThreadPool class in C++11. Following is relevant parts from the code:
- whenever
enqueue
is called on the threadPool object, it binds the passed function with all passed arguments, to create ashared_ptr
ofstd::packaged_task
:
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
extracts the
future
from thisstd::packaged_task
to return to the caller and stores thistask
in astd::queue<std::function<void()>> tasks;
.In the constructor, it waits for the task in queue, and if it finds one, it executes the task:
for(size_t i = 0;i<threads;++i)
workers.emplace_back(
[this]
{
for(;;)
{
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,[this]{ return !this->tasks.empty(); });
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
}
);
Now, based on this, following is my questions:
If
std::packaged_task
was stored in astd::queue<std::function<void()>>
, then it just becomes astd::function
object, right? then how does it still write to the shared state ofstd::future
extracted earlier?If stored
std::packaged_task
was not just astd::function
object but still astd::packaged_task
then when astd::thread
executestask()
through a lambda (code inside constructor), then why doesn't it run on another thread? asstd::packaged_task
are supposed to run on another thread, right?
As my questions suggest, I am unable to understand the conversion of std::packaged_task
into std::function
and the capability of std::function
to write to the shared state of std::future
. Whenever I tested this code with n threads, the maximum number of thread ids I could get was n but never more than n. Here is the complete code (including that of ThreadPool
and it also includes a main function which counts the number of threads created).