当我运行以下并行代码时,在第18行(两次打印之间)的分配中遇到了分段错误。我不太了解是什么原因造成的。
这是描述问题的最小工作示例:

#include <iostream>
#include <numeric>
#include <vector>
#include <thread>


struct Worker{

    std::vector<int>* v;

    void f(){

        std::vector<int> a(20);
        std::iota(a.begin(), a.end(), 1);

        auto b = new std::vector<int>(a);
        std::cout << "Test 1" << std::endl;
        v = b;
        std::cout << "Test 2" << std::endl;
    }
};

int main(int argc, char** argv) {

    int nw = 1;

    std::vector<std::thread> threads(nw);
    std::vector<std::unique_ptr<Worker>> W;

    for(int i = 0; i < nw; i++){
        W.push_back(std::make_unique<Worker>());
        threads[i] = std::thread([&]() { W[i]->f(); } );

        // Pinning threads to cores
        cpu_set_t cpuset;
        CPU_ZERO(&cpuset);
        CPU_SET(i, &cpuset);
        pthread_setaffinity_np(threads[i].native_handle(), sizeof(cpu_set_t), &cpuset);
    }

    for (int i = 0; i < nw; i++) {
        threads[i].join();
        std::cout << (*(W[i]->v))[0] << std::endl;
    }

}
似乎使用-fsanitize = address编译该代码可以正常工作,但性能却最差。我该如何运作?

最佳答案

除了Sam提到的 vector 同步问题之外,还有另一个问题。
这行:

threads[i] = std::thread([&]() { W[i]->f(); } );
通过引用捕获i。在线程开始运行之前,i很可能超出范围(并被破坏)。语句W[i]->f();可能会读取i的无效值,该值是负数或太大。请注意,在i超出范围之前,最后写入该值的是nw,因此,即使先前包含i的内存仍然可以访问,它的nw值也可能太大。
您可以通过按值捕获i来解决此问题:
threads[i] = std::thread([&W, i]() { W[i]->f(); } );
//                        ^^^^^
// captures W by reference, and i by value

10-06 01:56