在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*/
Run Code Online (Sandbox Code Playgroud)
此外,如果更改将有利于性能,请随时推荐另一个线程std::thread.
首先std::thread不返回值,但在构造时传递给它的函数可能很好.
std::thread除非在线程上调用函数后以某种方式保存它,否则无法从对象访问函数的返回值.
一个简单的解决方案是例如将引用传递给线程并将结果存储在引用指向的内存中.有了线程,但必须注意不要引入数据竞争.
考虑一个简单的功能:
int func() {
return 1;
}
Run Code Online (Sandbox Code Playgroud)
这个例子:
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;
Run Code Online (Sandbox Code Playgroud)
现在,您可以使用标准库,而不是自己处理这种低级并发内容,因为有人(一如既往)已经为您解决了这个问题.有std::packaged_task与std::future它被设计工作std::thread于这一特定类型的问题.在大多数情况下,它们也应该与自定义解决方案一样高效.
这是使用std::packaged_task和的等效示例std::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.
Run Code Online (Sandbox Code Playgroud)
不要总是认为某些东西效率低下只是因为它被认为是"高水平".
使用线程并终止它需要数百个机器周期.但这只是一个开始.如果线程正在做任何有用的事情,线程之间的上下文切换将会重复消耗甚至数百个机器周期.所有这些线程的执行上下文将消耗许多字节的内存,这反过来会使许多一行缓存陷入困境,从而阻碍了CPU的工作量,这又耗费了数百个机器周期.
事实上,做多任务处理是数百个机器周期的重要消费者.当你设法让足够的处理器处理概念上独立的数据块(因此并行处理不会威胁到它们的完整性)并且大到足以显示与单处理器版本相比的净增益时,多任务仅在CPU功率使用方面变得有利可图.
在所有其他情况下,多任务处理在所有领域本质上都是低效的,但其中一个:反应性.任务可以非常快速而精确地对外部事件做出反应,最终来自一些外部H/W组件(无论是定时器的内部时钟还是网络流量的WiFi /以太网控制器).
这种在不浪费CPU的情况下等待外部事件的能力提高了整体CPU效率.就是这样.
就其他性能参数(内存消耗,内核调用内部浪费的时间等)而言,启动新线程总是一个净损失.
简而言之,多任务编程的艺术归结为:
多处理器架构正在增加一个新的复杂程度,因为任何程序现在都可以被视为一个具有许多外部CPU的进程,可以用作额外的电源.但是你的问题似乎与此无关.
多任务处理效率的度量将最终取决于给定程序预期在给定的一组反应性限制内同时处理的外部事件的数量.
最后我来谈谈你的具体问题.
为了对外部事件作出反应,每次在蚁丘周围移动新的枝条或死虫时都会启动任务,这是一种非常粗糙和低效的方法.
您可以使用许多强大的同步工具,这些工具允许您在单个任务上下文中以(近乎)最优的效率(几乎无成本)对一堆异步事件做出反应.
通常,阻塞等待多个输入,例如unix-flavoured select()或Microsoft的WaitForMultipleEvents()对应.
使用这些将为您提供无与伦比的性能提升,比您可以从您的任务 - 结果 - 收集 - 优化项目中挤出的几十个CPU周期更大.
所以我的答案是:根本不需要优化线程设置.这不是问题.
花在重新思考架构上的时间会更好,这样一些经过深思熟虑的线程就可以取代当前设计产生的大量无用的CPU和内存耗尽.
| 归档时间: |
|
| 查看次数: |
4997 次 |
| 最近记录: |