异步函数产生不一致的结果
asynchronous function producing inconsistent results
我有一个异步运行的函数。不幸的是,它只是偶尔吐出正确的答案。每次运行代码时,由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
。因此,一旦为函数调用minor(i, 0)
评估了i
,它可能已经改变了。更糟糕的是,在循环结束之前,函数调用可能还没有执行。因此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();
}));
}
你还应该避免对你的未来向量进行重新定位。只需在循环之前添加futures.reserve(rows)
即可。
相关文章:
- 如何查找导致结果不一致的代码
- 结果与 fstream::read 不一致
- 使用迭代器对向量的C 递归初始化产生不一致的结果
- boost::d ynamic_bitset 与 std::vector 的结果不一致<bool>?
- 使用不同的表达式计算同一整数时的结果不一致
- RapidJSON 在转换为字符串时产生不一致的结果
- 使用两种不同的方法遍历 Vector 的结果不一致
- GDI打印API StartDoc函数给出的结果不一致
- 位掩码结果不一致
- is_assignable<>结果不一致
- opencvmatchTemplate在计算机之间给出不一致的结果
- CPPCheck返回不一致的结果
- 异步函数产生不一致的结果
- 使用 strptime/strftime 的结果不一致
- 在opencv中findChessboardCorners()的结果不一致
- CUDA 共享内存 - 结果不一致
- C++/CImg结果不一致
- 从文件中读取的浮点值与计算结果不一致
- std::regex_search与gcc 4.9.1的结果不一致
- 不同架构下的浮点结果不一致!!如何继续