首页 > 解决方案 > 在 C++ 中将线程存储在向量中

问题描述

我正在学习并行编程,我的讲座中有一个例子。我们有一个用于存储 20 个斐波那契数的数组,基本上,为了计算每个数,创建了一个线程。这是斐波那契函数的代码:

unsigned int fibonacci(unsigned int n) {
    if(n==0)
        return 0;

    unsigned int f0 = 0, f1 = 1, f2;
    for (auto i=1u; i < n; i++) {
        f2 = f0 + f1;
        f0 = f1;
        f1 = f2;
    }
    return f1;
}

这是主要方法的代码:

int main(int argc, char **argv) {
    std::vector<std::thread> threads;
    unsigned int results[20];

    for(auto i=0u; i < 20; i++) {
        auto f = rand() % 30;
        threads.push_back(std::thread([&](){
            results[i] = fibonacci(f);
        }));
    }

    std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));

    for(auto& r: results) {
        std::cout << r << " ";
    }
    std::cout << std::endl;

    return 0;
}

计算了数字,但程序以状态-1073741819 (0xC0000005)终止。我关注了这篇文章,但即使应用emplace.back()也没有任何变化。那么这个错误的原因可能是什么?

标签: c++multithreading

解决方案


您的问题是范围(还有其他问题):

for(auto i=0u; i < 20; i++) {
    // This value is reinitialized every loop.
    // Though it is likely that every loop will use the same
    // physical memory location for f this is not guaranteed by
    // the standard (especially if the loop is unrolled)
    auto f = rand() % 30;

    // Here you are capturing i, f, results by reference.
    // Because they are captured by reference your main
    // thread and the created thread are both referencing the same object.
    // 
    // One thread is modifying i, f the other is reading these value.
    // There is no attempt to make sure that the objects are accessed
    // between memory barriers (I am not sure what the modern terms are
    // thus you don't know what values you will be getting).
    threads.push_back(std::thread([&](){
        results[i] = fibonacci(f);
    }));
}
// At this point both the variable f and the variable i are out of scope.
// technically they do not exist and thus the references captured by
// the threads point to memory locations with a non live object.
//
// These locations are more than likely being used for other variables.
//
// If one of the threads accesses these memory locations after the main
// thread reaches this point then you have undefined behavior.

有几个解决方案。

按值传递 i, f

如果您为线程提供自己的副本,i那么f您将不会遇到共享访问或访问生命周期已结束的对象的问题。

    // still need to capture results by reference.
    threads.push_back(std::thread([i, f, &results](){
        results[i] = fibonacci(f);
    }));

保留所有值f并传递对这些值的引用。

unsigned int results[20];
// have an array of f one value for each thread.
int f[20];

for(auto i=0u; i < 20; i++) {
    // Assign the random to the correct location in f.
    f[i] = rand() % 30;

    // Pass references f[i] and results[i]
    // Once the reference has been captured the value of i
    // is no longer needed.
    threads.push_back(std::thread([&f = f[i], &result = results[i]](){
                result = fibonacci(f);
                }));
}

推荐阅读