是什么导致了 std::async 中的数据争用?
What is causing data race in std::async here?
我最近在康威的生命游戏中创建了一个模式搜索程序,但是运行太慢了,不实用。
所以我决定将它并行化,但我失败了;它导致了分段错误,这很可能是由于数据竞争造成的。
代码简单解释:
/* ... */
#include <list>
#include <mutex>
#include <future>
#include <iostream>
#include <forward_list>
int main() {
/* ... */
while (true) {
/* ... */
std::forward_list</*pattern type*/> results;
std::list<std::future<void>> results_future;
std::mutex results_mutex;
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&]{
/*A very hard calculation*/
if (/*The pattern is what I'm looking for*/) {
std::lock_guard<std::mutex> results_guard(results_mutex);
results.push_front(std::move(/*The pattern*/));
}
}));
while (!results_future.empty()) {
results_future.front().wait();
results_future.pop_front();
}
if (!results.empty()) {
for (auto &res : results)
std::cout << "Pattern found:" << std::endl << res;
return 0;
}
}
}
我很确定 results
是唯一声明在 lambda 表达式的函数范围之外并在那里被修改的对象,所以我用互斥锁锁定了它。
但数据竞赛仍然存在。那么是什么原因造成的呢?
我发现问题与 lambda 捕获有关:
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&]{
/*pattern type*/ patt_orig = search_grid;
/* ... */
}));
search_grid
,如上面 SingerOfTheFall 的评论所述,是通过引用捕获的。并在 lambda 范围内转换为模式类型。问题是 search_grid
可以修改 而 它正在转换为模式类型,反之亦然。数据竞赛!
转换必须在 lambda 捕获内:
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&, patt_orig = (/*pattern type*/)search_grid]{
/* ... */
}));
现在一切正常。
我最近在康威的生命游戏中创建了一个模式搜索程序,但是运行太慢了,不实用。
所以我决定将它并行化,但我失败了;它导致了分段错误,这很可能是由于数据竞争造成的。
代码简单解释:
/* ... */
#include <list>
#include <mutex>
#include <future>
#include <iostream>
#include <forward_list>
int main() {
/* ... */
while (true) {
/* ... */
std::forward_list</*pattern type*/> results;
std::list<std::future<void>> results_future;
std::mutex results_mutex;
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&]{
/*A very hard calculation*/
if (/*The pattern is what I'm looking for*/) {
std::lock_guard<std::mutex> results_guard(results_mutex);
results.push_front(std::move(/*The pattern*/));
}
}));
while (!results_future.empty()) {
results_future.front().wait();
results_future.pop_front();
}
if (!results.empty()) {
for (auto &res : results)
std::cout << "Pattern found:" << std::endl << res;
return 0;
}
}
}
我很确定 results
是唯一声明在 lambda 表达式的函数范围之外并在那里被修改的对象,所以我用互斥锁锁定了它。
但数据竞赛仍然存在。那么是什么原因造成的呢?
我发现问题与 lambda 捕获有关:
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&]{
/*pattern type*/ patt_orig = search_grid;
/* ... */
}));
search_grid
,如上面 SingerOfTheFall 的评论所述,是通过引用捕获的。并在 lambda 范围内转换为模式类型。问题是 search_grid
可以修改 而 它正在转换为模式类型,反之亦然。数据竞赛!
转换必须在 lambda 捕获内:
for (/*All the possible unique pattern in given grid*/)
results_future.push_back(std::async([&, patt_orig = (/*pattern type*/)search_grid]{
/* ... */
}));
现在一切正常。