将结果从线程转储到向量中是否安全?

Too*_*one 0 c++ multithreading c++11

我正在学习C++ 11的功能,并按照以下几行编写了一些代码

#include <vector>
#include <thread>
using std::thread;
using std::vector;

double Computation(int arg)
{
    // some long-running computation
    return 42.0;
}

double ConcurrentComputations()
{
    const int N = 8; // number of threads
    vector<thread> thr;
    vector<double> res(N);
    const int arg = 123456; // something or other
    // Kick off threads which dump their results into res
    for(int i=0; i<N; ++i)
        thr.push_back(thread ([&res, i, arg]()
                {  res[i] =  Computation(arg); } ));
    // Wait for them to finish and get results
    double sum = 0;
    for(int i=0; i<N; ++i) {
        thr[i].join();
        sum += res[i];
    }
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

在寒冷的白天再看一遍,我认为我真的不应该vector在lambda函数中引用a 并将数据转储到其中.我正在考虑将矢量作为常规数组并依赖于operator[]简单添加的i实现&res.front()(也许我应该已经捕获了&res.front(),现在我已经在Stroustrup 4ed中进一步阅读了,我可以看到我应该使用期货和承诺) .

然而,我的问题是,认为在实践中我可以逃脱我写的代码是否合理?

Cam*_*ron 5

你的代码实际上很好!(当混合线程时,默认情况下代码通常会被破坏,但在这种情况下不会.)

声明vector<double> res(N);将为所有结果初始化具有足够空间的数组,因此向量将永远不会在循环中调整大小.

每个线程只写入向量的不同元素,并且线程构造函数和join()方法中存在隐式内存屏障,这些屏障按照您的预期保持排序.

现在,关于这是否实际上是由标准支持 - 嗯,可能不是(我发现关于std :: vector的线程安全的大多数引用只保证读取,而不是写入).捕获前面也无济于事,因为你仍然以任何方式写入向量的元素.

(请注意,我个人在平台上成功使用了这种确切的模式而没有遇到任何问题.)