55

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

有没有什么好的方法可以在 C++11 中使用异步/未来范式来实现这一点?

乍一看,它看起来很简单,您只需生成多个任务:

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

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

然而,这里的问题是,未来的对象必须存储在某种队列中,并一个一个地等待。但是,可以一遍又一遍地迭代未来的对象,检查它们中的任何一个是否准备好,但由于不必要的 CPU 负载,这是不希望的。

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

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

还有其他更好的异步/未来解决方案吗?

4

4 回答 4

21

C++11 中的线程支持只是第一步,虽然std::future很牛逼,但它还不支持多重等待。

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

std::future这个系统中并没有添加太多功能,并且让任务直接声明它们已准备好并将其结果粘贴到上述队列中会更有效。如果你走这条路,你可以编写匹配std::asyncor模式的包装器std::thread,并返回一个std::future表示队列消息的类似对象。这基本上涉及重新实现并发库的一部分。

如果您想保留s std::future,您可以创建shared_futures,并让每个相关任务依赖于shared_futures 集:即,无需中央调度程序即可。这不允许诸如中止/关闭消息之类的事情,我认为这对于强大的多线程任务系统至关重要。

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

于 2013-10-07T15:42:27.393 回答
6

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

于 2013-10-07T12:54:07.980 回答
1

facebook 的愚蠢在期货上有 collectAny/collectN/collectAll,我还没有尝试过,但看起来很有希望。

于 2021-11-15T09:54:53.683 回答
0

鉴于“Wating for multiple futures”的标题会吸引人们提出诸如“是否需要等待所有期货列表?”之类的问题。您可以通过跟踪待处理的线程来充分做到这一点:

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);
}

完整的例子

可以将std::experimental::when_all与扩展运算符一起使用

于 2020-03-15T16:34:56.540 回答