什么导致std :: async中的数据竞争?

时间:2017-02-03 11:56:39

标签: c++ parallel-processing mutex future stdasync

我最近在Conway的生命游戏中创建了一个模式搜索程序,但它运行得太慢而不实用 所以我决定将它并行化,但我失败了;它导致了分段错误,这很可能是由于数据竞争造成的 代码的简要说明:

/* ... */
#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-expression的函数范围内声明并在那里被修改的对象,所以我用互斥锁将其锁定。
但数据竞争仍然存在。是什么导致了它?

1 个答案:

答案 0 :(得分:0)

我发现问题与lambda捕获有关:

for (/*All the possible unique pattern in given grid*/)
    results_future.push_back(std::async([&]{
        /*pattern type*/ patt_orig = search_grid;
        /* ... */
    }));
如上文SingerOfTheFall的评论中所述,

search_grid通过引用而被捕获。并且它在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]{
        /* ... */
    }));

现在一切都还好。