gpt4 book ai didi

c++ - 异步函数产生不一致的结果

转载 作者:搜寻专家 更新时间:2023-10-31 00:12:57 32 4
gpt4 key购买 nike

我有一个异步运行的函数。不幸的是,它只是偶尔会吐出正确答案。每次运行代码时,futures[i].get() 表示的值都会改变。我是多线程的新手。

double async_func() const {

vector<future<double>> futures;

double val = 0;
for (int i = 0; i < rows; i++) {
futures.push_back(std::async(std::launch::async, [&] {return minor(i,0).determinant();}) );
}
for (int i = 0; i < rows; i++)
val += futures[i].get();

return val;
}

最佳答案

问题在于引用捕获。

for (int i = 0; i < rows; i++)
{
futures.push_back(std::async(std::launch::async, [&] // capture by reference!
{
return minor(i,0).determinant();
}));
}

这是一个问题,因为每个执行的方法都没有得到它自己的i值,而是对循环变量i的引用。因此,一旦 i 被评估用于函数调用 minor(i, 0),它可能已经改变。更糟糕的是,函数调用可能在循环结束之前尚未执行。因此 i 可能在使用之前就被销毁了。


如果上面的描述还不够,也许这个时间表可以提供帮助。请注意,这不是真实情况,只是一个例子。

假设迭代 i 需要 2 个时间步,评估函数的参数需要 2 个步骤,启动一个线程需要 5 个步骤(在真机上可能更多!)。每个线程完成的工作可能需要数千步(这就是我们将它们并行化的原因,对吗?)。

Time -->
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | | | | | | Thread 3 function call.
| | | | | | | | | | | | | Thread 3 evaluate parameters (i == garbage!).
| | | | | | | | | | | | Thread 3 start; Thread 2 function call.
| | | | | | | | | | | Thread 2 evaluate parameters (i == garbage!).
| | | | | | | | | | Destroy i; Thread 2 start; Thread 1 function call.
| | | | | | | | | Loop condition broken; Thread 1 evaluate parameters (i == 4 !).
| | | | | | | | Thread 0 function call; Thread 1 start; i = 4;
| | | | | | | Thread 3 request to start; Thread 0 evaluate parameters (i == 3 !).
| | | | | | Thread 0 start; i = 3;
| | | | | Thread 2 request to start.
| | | | i = 2.
| | | Thread 1 request to start.
| | i = 1.
| Thread 0 request to start.
Create i, i = 0.

所以一些线程获得有意义的数据,其他线程则不会。根据实际时间,可能会在评估其函数参数值的同时增加 i,在这种情况下,您会遇到竞争条件。


解决方法是按值捕获i:

for (int i = 0; i < rows; i++)
{
futures.push_back(std::async(std::launch::async, [=] // capture by value
{
return minor(i,0).determinant();
}));
}

建议:在处理异步位时,明确说明您捕获的内容:

for (int i = 0; i < rows; i++)
{
futures.push_back(std::async(std::launch::async, [i] // explicit capture by value
{
return minor(i,0).determinant();
}));
}

您还应该避免对您的 future vector 进行重新分配。只需在循环之前添加 futures.reserve(rows)

关于c++ - 异步函数产生不一致的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28730499/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com