我陷入了这样的多个异步问题
例:

void updateList(vector<int> &list, int value){
  list.push_back(value);
}

int main(){
   vector<future<void>> asyncTasks;
   vector<int> list;
   for(int i = 0; i < 10; i ++){
      asyncTasks.push_back(async(launch::async, updateList,i ));
   }

   for(auto &&f : asyncTasks){
      f.get();
   }
}


问题是有时会引发有关插入暴力的错误。

你能给我任何想法吗?

最佳答案

好了,问题是您在updateList中一次执行了两件事:


根据给定的索引计算值(通过计算,我的意思是仅使用它)
向容器添加值


并行执行第二个步骤没有多大意义,因为您必须在容器上进行序列化,否则会发生数据争用,这就是导致错误的原因。

void updateList(vector<int> &list, int value){
  list.push_back(value); //< Data race-> Undefined behavior -> Sometimes Crash
}


但是我们可以做可以轻松并行的工作,即1.值的计算。
如果我们只是在容器中添加虚拟零,首先,我们可以修改容器中的元素,即std::vector,因为我们不修改容器本身,例如计数或顺序,仅修改其成员。

所以之后您可以并行计算,但是为什么不直接使用新的并行算法为我们做呢?因此,我添加了第二个解决方案。

同样,这一发现也可以在阿姆达尔定律中找到您无法完成的工作和可以进行的工作。

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <execution>
#include <future>


//Your modified solution
void updateList(std::vector<int> &list, int value){
    const auto index = value;
    //Do the heavy stuff here
    list[index]  = value;
}

int main(){

    std::vector<int> list(10);
    std::vector<std::future<void>> asyncTasks;
    for(int i = 0; i < 10; i ++){
        asyncTasks.emplace_back(std::async(std::launch::async, &updateList, std::ref(list), i));
    }
    for(auto &f : asyncTasks){
        f.get();
    }

    std::for_each(list.begin(),list.end(), [](auto v) {std::cout << v << " ";});
    std::cout << "\n";
}


//Better solution:

int heavy_work_calculation(int input) {
    //Do the heavy stuff here
    return input;
}

int main(){

    std::vector<int> list(10);
    std::iota(list.begin(), list.end(), 0);
    std::transform(std::execution::par_unseq, list.begin(), list.end(),
                    list.begin(), heavy_work_calculation);

    std::for_each(list.begin(),list.end(), [](auto v) {std::cout << v << " ";});
    std::cout << "\n";
}

09-06 03:17