从C ++ 11中的线程返回一个值

时间:2014-01-13 02:09:42

标签: c++ c++11

在C ++ 11中从线程返回值的最有效方式是什么?

vector<thread> t(6);

for(int i = 0; i < 6; i++)
    t[i] = thread(do_c);

for(thread& t_now : t)
    t_now.join();

for(int i = 0; i < 6; i++)
    cout << /*the return of function do_c*/

此外,如果更改将有助于提高性能,请随时推荐另一个线程,而不是std::thread

2 个答案:

答案 0 :(得分:6)

首先std::thread不返回值,但在构造时传递给它的函数可能会很好。

除非你在线程上调用函数后以某种方式保存它,否则无法从std::thread对象访问函数的返回值。

一个简单的解决方案就是将引用传递给线程并将结果存储在引用指向的内存中。使用线程虽然必须注意不要引入数据竞争

考虑一个简单的功能:

int func() {
    return 1;
}

这个例子:

std::atomic<int> x{0}; // Use std::atomic to prevent data race.

std::thread t{[&x] {   // Simple lambda that captures a reference of x.
    x = func();        // Call function and assign return value.
}};

/* Do something while thread is running... */

t.join();

std::cout << "Value: " << x << std::endl;

现在,您可以使用标准库而不是自己处理这种低级别的并发内容,因为有人(一如既往)已经为您解决了这个问题。 std::packaged_taskstd::future设计用于针对此特定类型的问题与std::thread一起使用。在大多数情况下,它们也应该与自定义解决方案一样高效。

以下是使用std::packaged_taskstd::future

的等效示例
std::packaged_task<int()> task{func}; // Create task using func.
auto future = task.get_future();      // Get the future object.

std::thread t{std::move(task)};       // std::packaged_task is move-only.

/* Do something while thread is running... */

t.join();

std::cout << "Value: " << future.get() << std::endl; // Get result atomically.

不要总是认为某些东西效率低下只是因为它被认为是“高水平”。

答案 1 :(得分:5)

使用线程并终止它需要数百个机器周期。但这只是一个开始。如果线程正在做任何有用的事情,线程之间的上下文切换将会重复消耗甚至数百个机器周期。所有这些线程的执行上下文将消耗许多字节的内存,这反过来会破坏许多缓存行,从而阻碍了CPU在数百个机器周期中的大量工作。

事实上,做多任务的任何事情都是数百个机器周期的重要消费者。当您设法让足够的处理器处理概念上独立的数据块时,多任务只会在 CPU功率使用 方面变得有利可图(因此并行处理不会威胁到它们的完整性)并且大到足以显示与单处理器版本相比的净增益。

在所有其他情况下,多任务处理在所有域中本质上都是低效的,只有一个: 反应性 。任务可以非常快速而精确地对外部事件做出反应,最终来自一些外部H / W组件(无论是定时器的内部时钟还是网络流量的WiFi /以太网控制器)。

这种在不浪费CPU的情况下等待外部事件的能力提高了整体CPU效率。就是这样。
就其他性能参数(内存消耗,内核调用内部浪费的时间等)而言,启动新线程始终是净损失

简而言之,多任务编程的艺术归结为:

  • 识别您必须处理的外部I / O流
  • 考虑反应性要求(记住更多反应性= 99%的时间内CPU /内存效率更低)
  • 以合理的效率/易维护性妥协为所需事件设置处理程序。

多处理器架构正在增加一个新的复杂程度,因为任何程序现在都可以被视为一个具有许多外部CPU的进程,可以用作额外的电源。但是你的问题似乎与此无关。

多任务处理效率的衡量标准最终将取决于预期给定程序在给定的反应性限制范围内同时处理的外部事件的数量。< / p>

最后,我提出了你的具体问题。

为了对外部事件做出反应,每次在蚁丘周围移动新的枝条或死虫时都会启动任务,这是一种非常粗糙和低效的方法。

您可以使用许多功能强大的同步工具,这样您就可以在单个任务环境中以(近乎)最佳效率(几乎)免费对一堆异步事件作出反应。
通常,阻止等待多个输入,例如unix风格的select()或Microsoft的WaitForMultipleEvents()对应。

使用这些将为您提供无与伦比的性能提升,比您可以从您的任务 - 结果 - 收集 - 优化项目中挤出的几十个CPU周期大得多。

所以我的答案是:根本不需要优化线程设置。这不是问题。

你的时间会更好地重新考虑你的架构,以便一些经过深思熟虑的线程可以取代当前设计产生的大量无用的CPU和内存耗尽。