threadpool c ++实现问题

ami*_*421 6 c++ concurrency multithreading threadpool

在这里这里,我们可以看到类似的线程池实现.

我的问题是关于将任务添加到线程池的功能,这些是分别在上面的项目中添加排队.

因为这些看起来非常相似我在这里张贴了一块(来自第二个项目)

auto ThreadPool::enqueue(F&& f, Args&&... args) 
-> std::future<typename std::result_of<F(Args...)>::type>
{
    using return_type = typename std::result_of<F(Args...)>::type;

    auto task = std::make_shared< std::packaged_task<return_type()> >(
        std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );

    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);

    // don't allow enqueueing after stopping the pool
        if(stop)
            throw std::runtime_error("enqueue on stopped ThreadPool");

        tasks.emplace([task](){ (*task)(); });
    }
    condition.notify_one();
    return res;
}
Run Code Online (Sandbox Code Playgroud)

容器任务声明为:

std::queue< std::function<void()> > tasks;
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 为什么使用附加包装器std :: function声明的任务围绕任务变量?为什么任务的队列没有被声明为std :: packaged_task的容器,它也是一个可调用的对象?我认为任务队列应包含没有参数且没有返回类型的"通用"可调用对象.所以通过绑定实现删除参数,额外的包装器std :: function有助于删除返回类型,是正确还是不正确?还有关于shared_ptr的使用 - 是否只是为了避免package_task是可移动类型但std :: function是可复制的冲突?
  2. 对所有线程使用一个共享任务队列是一个好习惯吗?我在看Anthony Williams"C++ Concurrency in action",他建议避免这种情况以防止缓存行争用.并且他建议使用更高级的技术和两个级别的队列 - global和thread_local用于工作者的线程.

Mik*_*yke 2

如果您仍在寻找答案(您大多是自己回答的):

  1. 正如你所想的那样。
  2. 这不是“不好的做法”。它只会导致性能下降,不仅因为缓存行争用,还因为任务列表上的争用。

当前的 HPC 线程池实现主要使用工作窃取调度程序:每个工作线程都有自己的队列。工作人员从自己的队列中拉取工作或将工作推送到自己的队列中,直到完成自己的队列中的所有任务。然后它从其他工作人员那里窃取任务并执行这些任务。