等待多个期货?

时间:2013-10-07 12:48:51

标签: c++ multithreading c++11

我想运行相同类型的任务(工作线程),但一次只能执行一定数量的任务。当任务完成时,其结果是新任务的输入,然后可以启动该任务。

有没有什么好方法可以在C ++ 11中使用async / future范例来实现它?

乍一看,它看起来很直接,你只需要产生多个任务:

std::future<T> result = std::async(...);

然后,运行result.get()以获取任务的异步结果。

然而,这里的问题是未来的对象必须存储在某种队列中并逐个等待。但是,可以反复遍历未来的对象,检查它们是否已准备好,但由于不必要的CPU负载,这是不可取的。

是否有可能以某种方式等待来自给定集合的任何未来准备好并获得其结果?

到目前为止,我能想到的唯一选择是没有任何异步/未来的老派方法。具体来说,产生多个工作线程并在每个线程的末尾将其结果推送到受互斥锁保护的队列中,该队列通过条件变量通知等待线程,该条件变量已更新队列以获得更多结果。

是否还有其他更好的async / future解决方案?

3 个答案:

答案 0 :(得分:17)

C ++ 11中的线程支持只是第一次传递,而std::future虽然摇摆不定,但它还不支持多次等待。

但是,你可以相对低效地伪造它。您最终为每个std::future(哎哟,非常昂贵)创建一个帮助程序线程,然后将他们的“这个future准备好”收集到一个同步的多生产者单一消费者消息队列中,然后设置一个消费者任务,发送给定std::future准备就绪的事实。

此系统中的std::future不会添加太多功能,并且具有直接表明它们已准备就绪并将结果粘贴到上述队列中的任务将更有效。如果你走这条路线,你可以编写与std::asyncstd::thread模式相匹配的包装器,并返回一个代表队列消息的std::future对象。这基本上涉及重新实现并发库的一大块。

如果你想留在std::future,你可以创建shared_future,让每个依赖任务都依赖于shared_future的集合:即,没有中央调度程序。这不允许中止/关闭消息之类的事情,我认为这对于强大的多线程任务系统至关重要。

最后,您可以等待C++2x,或者将并发TS折叠到标准中,以便为您解决问题。

答案 1 :(得分:6)

你可以创建“第1代”的所有未来,并将所有这些期货交给你的第2代任务,然后他们将自己等待他们的输入。< / p>

答案 2 :(得分:1)

鉴于“等待多个期货”标题吸引了诸如“是否需要等待所有期货清单?”之类的问题。您可以通过跟踪挂起的线程来充分做到这一点:

unsigned pending = 0;
for (size_t i = 0; i < N; ++i) {
    ++pending;
    auto callPause =
        [&pending, i, &each, &done]()->unsigned {
            unsigned ret = each();
            results[i] = ret;
            if (!--pending)
                // called in whatever thread happens to finish last
                done(results);
            return ret;
        };
    futures[i] = std::async(std::launch::async, each);
}

full example

也许可以将std::experimental::when_all与传播运算符一起使用