Multithreading C++;操作线程池运行中的并发性
我正在读Anthony Williams的《C++并发操作》这本漂亮的书,第一版。在第9.1.4章(相关源代码可在上获得)中,提供了一个线程池,该线程池使用属于该池的每个工作线程的本地队列,避免了对要执行的任务的全局队列的争用。相关示例代码如下所示:Multithreading C++;操作线程池运行中的并发性,multithreading,c++11,Multithreading,C++11,我正在读Anthony Williams的《C++并发操作》这本漂亮的书,第一版。在第9.1.4章(相关源代码可在上获得)中,提供了一个线程池,该线程池使用属于该池的每个工作线程的本地队列,避免了对要执行的任务的全局队列的争用。相关示例代码如下所示: class thread_pool { thread_safe_queue<function_wrapper> pool_work_queue; typedef std::queue<function_wrapp
class thread_pool
{
thread_safe_queue<function_wrapper> pool_work_queue;
typedef std::queue<function_wrapper> local_queue_type;
static thread_local std::unique_ptr<local_queue_type>
local_work_queue;
void worker_thread()
{
local_work_queue.reset(new local_queue_type);
while(!done)
{
run_pending_task();
}
}
public:
template<typename FunctionType>
std::future<std::result_of<FunctionType()>::type>
submit(FunctionType f)
{
typedef std::result_of<FunctionType()>::type result_type;
std::packaged_task<result_type()> task(f);
std::future<result_type> res(task.get_future());
if(local_work_queue)
{
local_work_queue->push(std::move(task));
}
else
{
pool_work_queue.push(std::move(task));
}
return res;
}
void run_pending_task()
{
function_wrapper task;
if(local_work_queue && !local_work_queue->empty())
{
task=std::move(local_work_queue->front());
local_work_queue->pop();
task();
}
else if(pool_work_queue.try_pop(task))
{
task();
}
else
{
std::this_thread::yield();
}
}
// rest as before
};
类线程池
{
线程\安全\队列池\工作\队列;
typedef std::queue local_queue_type;
静态线程\u本地标准::唯一\u ptr
本地工作队列;
无效工作线程()
{
本地工作队列。重置(新的本地队列类型);
而(!完成)
{
运行挂起的任务();
}
}
公众:
模板
未来
提交(功能类型f)
{
typedef std::result_of::type result_type;
std::打包任务(f);
std::future res(task.get_future());
if(本地工作队列)
{
本地工作队列->推送(标准::移动(任务));
}
其他的
{
pool_work_queue.push(std::move(task));
}
返回res;
}
无效运行挂起的任务()
{
功能包装任务;
if(本地工作队列&!本地工作队列->空()
{
task=std::move(本地工作队列->前台());
本地工作队列->弹出();
任务();
}
else if(池\工作\队列。尝试\弹出(任务))
{
任务();
}
其他的
{
std::this_thread::yield();
}
}
//照旧休息
};
特别是,当调用thread_pool::submit函数时,如果在工作线程上调用该函数,则会将该任务推送到线程的本地队列上,否则会将该任务推送到全局任务队列上。我的问题是:
这种功能对我来说没有意义,如何从工作线程调用线程池::submit?我设想所有提交API调用都将从thread_Pool类管理的池外的“客户端”线程执行,因此对于它们来说,与本地队列相关的thread_局部变量将始终为null,然后,任务将在全局队列中排队……当然,我遗漏了一些东西,因为我不明白提议的解决方案是如何工作的。
提前感谢您的帮助 “如何从工作线程调用线程池::submit
?”线程上运行的任务可能会将另一个任务排入队列。task()
call中运行着任意代码。因此,提交的任务()应该反过来执行另一个提交()?我不认为这是预期的功能,除了性能问题(任务在移动到本地队列之前,无论如何都会存储在全局队列中),我不认为客户机打算知道线程池类的实现细节以便使用它,“移动到本地队列”是什么意思?所示代码的任何部分都不会从全局队列检索任务并将其放入本地队列。此优化的要点是,在工作线程上执行的submit
调用不会将任务放在全局队列上,而是直接放在本地队列上。这是local\u work\u queue
可以变为非空的唯一机制。“如何从工作线程调用thread\u pool::submit
?”线程上运行的任务可以将另一个任务排队。task()
call中运行着任意代码。因此,提交的任务()应该反过来执行另一个提交()?我不认为这是预期的功能,除了性能问题(任务在移动到本地队列之前,无论如何都会存储在全局队列中),我不认为客户机打算知道线程池类的实现细节以便使用它,“移动到本地队列”是什么意思?所示代码的任何部分都不会从全局队列检索任务并将其放入本地队列。此优化的要点是,在工作线程上执行的submit
调用不会将任务放在全局队列上,而是直接放在本地队列上。这是local\u work\u queue
变为非空的唯一机制。