让预定义数量的线程计算更多的任务

时间:2014-08-26 06:48:39

标签: c++ multithreading c++11

我有预定义数量的任务(任务对象)和预定义数量的线程。

我们假设8个线程和32个任务。

我当前的解决方案允许我并行运行8个任务,一旦完成,再并行运行8个任务。

有了这个解决方案,7个任务将不得不等待最慢的任务。

我想要一个解决方案,一旦一个线程完成它的任务,它将直接重新运行一个新任务,直到没有任何一个。

我目前的实施:

vector <Task> tasks; //the 32 tasks
unsigned int maxThreadCount(8);

for ( unsigned int i = 0; i < tasks.size() - maxThreadCount; i+=maxThreadCount )
{
    vector <thread> threads;
    for (unsigned int j = 0; j < maxThreadCount; ++j)
        threads.push_back (thread(std::bind( &Task::some_function, tasks[i+j])));

    for ( auto &i : threads)
        i.join();
}

4 个答案:

答案 0 :(得分:3)

您是否考虑过使用队列存储任务,并让每个线程从队列中弹出一个Task来处理它?像这样:

http://vichargrave.com/multithreaded-work-queue-in-c/

答案 1 :(得分:3)

这有点像黑客,显然特定于你的需求。我们的想法是让线程不断提取数据并将其发送到您的成员函数,直到任务列表用完为止,此时每个线程都会终止该发现。

这样的事情:

static void ThreadProc(
    std::vector<Task>& tasks,
    std::atomic_uint& idx, 
    void (Task::*member)())
{
    unsigned int i = 0;
    while ((i = idx++) < tasks.size())
        (tasks[i].*member)();
}

void RunTasks(
    std::vector<Task>& tasks, 
    unsigned int n_threads = std::max(std::thread::hardware_concurrency(),1U))
{
    // adjust number of threads to be no larger than the task set
    //  there is no reason to spin up new threads that will have
    //   nothing to do but exit.
    if (tasks.size() < n_threads)
        n_threads = tasks.size();

    // shared index into the task container        
    std::atomic_uint idx{0};

    // spin up the work crew
    std::vector<std::thread> threads;
    threads.reserve(n_threads);
    while (n_threads--)
    {
        threads.emplace_back(ThreadProc, 
                             std::ref(tasks), 
                             std::ref(idx), 
                             &Task::some_function);
    }

    for (auto &t : threads)
        t.join();
}

对于一组固定的任务,这与thread-proc invoke-member模型可以获得的一样简单。它不需要额外的容器&#39;队列&#39 ;;任务向量就足够了。并且它不需要锁定对象,而是使用更轻的原子。

显然,如果您需要增强的容器访问权限,这一切都会消失,例如在任务向量中间添加新项目等等。对于类似的东西,需要采用不同的方法,但对于单次工作-crew接近固定列出的任务这很难被击败。根据您的描述,这就是您所需要的。

祝你好运。

答案 2 :(得分:1)

使用Boost.Asio这很容易做到。只需从8个主题调用io_service::run方法,然后您就可以io_service::post将您的工作项io_service发送到{{1}}。可以找到一个示例here

答案 3 :(得分:1)

为什么不使用完整的并行处理库或语言扩展程序,例如。所有这些都非常便携,得到了主要操作系统和编译器的支持。

因此,您不必发明轮子,而是让库来处理线程和负载平衡;并防止你陷入这样的陷阱:Why is OpenMP outperforming threads?

例如,任务向量可以通过默认的线程数并行运行,如下所示:

cilk_for(int i = 0; i < tasks.size(); i++)
    task[i].some_function();

如果需要,您还可以更改线程数。