c++ - 在访问工作线程的 lambda 中捕获的 vector 列表中的元素的引用时,是否需要互斥锁?

标签 c++ multithreading thread-safety

我有以下代码:

#include <vector>
#include <thread>
#include <boost/range/irange.hpp>

...

{
    using namespace std;

    unsigned cpus = 8; // number of threads
    vector<vector<uint64_t>> aprimes(cpus);
    vector<thread> workers;
    for(int cpu: boost::irange(cpus)){
        vector<uint64_t>& tprimes = aprimes[cpu];
        workers.push_back(thread([=, &tprimes](){
            // top work on tprimes
            tprimes.push_back(5);
        }));
    }
    for_each(workers.begin(), workers.end(), [](thread &t)
    {
        t.join();
    });
    for(auto vec: aprimes){
        for(int val: vec){
            cout << val << endl;
        }
    }
}

我正在为每个线程中使用的 lambda 捕获对我的 vector aprimes 列表中每个 vector (tprimes) 的引用。这种捕获安全吗?我应该在这里使用互斥锁还是其他访问方法?该代码确实有效,但我不确定稍后是否会失败。

最佳答案

是的,这是安全的。当我们谈论数据竞争和未定义行为时,我们谈论的是多个线程修改同一个共享对象。在你的情况下你没有这个。 aprimes的每个元素是它自己的不同对象,所以每个工作线程都在处理它正在访问的对象。即使它们都恰好在里面 aprimes只要你不修改 aprimes 就不会改变这个.在那种情况下,就像声明了一堆 vector 一个接一个。

唯一需要注意的是你的主线程不允许修改aprimes并且不允许修改 aprimes 中的任何元素.如果这样做,那么您将有多个线程在没有同步的情况下写入共享对象,这是数据竞争和未定义的行为。


请注意,执行此操作时可能发生的一件事是 false sharing .如果你有一个 vector<int>有 4 个元素,每个线程都得到一个整数,那么即使没有线程共享该对象,它们也会共享对象所在的缓存行。这会导致 CPU 在一个时必须不断地同步 CPU 缓存整数的更新是因为它只能在缓存行级别上工作。这实际上将使程序像没有线程一样运行,因为所有 4 个线程不能同时修改缓存行。在这种情况下,因为我们正在处理 vector ,所以这应该不是问题,但需要注意这一点。

关于c++ - 在访问工作线程的 lambda 中捕获的 vector 列表中的元素的引用时,是否需要互斥锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57081899/

相关文章:

c++ - 如何使用 OpenMP 以线程安全的方式生成随机数

c# - 如何在 C# .Net 4.0 中重启线程?

c++ - C/C++中的 `_dl_init`(程序初始化)执行是单线程的吗?

java - 以下实用程序类是线程安全的吗?

c++ - 在 S 型神经网络 C++ 中使用反向传播,异或总是向 0.5 收敛

C++检查unicode字符是否为全角

c++ - C++ 上下文中的执行程序模式是什么?

python - Python 中的线程

java - 如何设置线程上运行的各个任务的最大执行时间?

c++ - QML:文档完全加载时触发的事件