在为工作线程访问 lambda 中捕获的向量列表中的元素引用时,是否需要互斥锁?
Is a mutex required when accessing references for elements in a list of vectors captured in a lambda for a worker thread?
我有以下代码:
#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 捕获对每个向量 (tprimes) 的向量 aprimes 列表中的引用。 这种捕获安全吗? 我应该在这里使用互斥锁还是其他访问方法? 代码确实有效,但我不确定以后是否会失败。
是的,这是安全的。 当我们谈论数据竞争和未定义的行为时,我们谈论的是修改同一共享对象的多个线程。 在您的情况下,您没有这个。aprimes
的每个元素都是它自己独特的对象,因此每个工作线程都在处理一个对象,只有它正在访问。 即使它们都碰巧在里面,只要你不修改aprimes
也不会改变这一点aprimes
. 在这种情况下,就像一个接一个地声明一堆向量一样。
唯一需要注意的是,您的主线程不允许修改aprimes
,也不允许修改aprimes
中的任何元素。 如果这样做,那么您将有多个线程写入共享对象而不同步,这是数据争用和未定义的行为。
请注意,执行此操作时可能发生的一件事是错误共享。 如果你有一个包含 4 个元素的vector<int>
,并且每个线程都得到一个整数,那么即使没有线程共享对象,它们也会共享对象所在的缓存行。 这会导致 CPU 在其中一个整数更新时不断必须同步 CPU 缓存,因为它只能在缓存行级别工作。 这有效地使程序像没有线程一样运行,因为所有 4 个线程都不能同时修改缓存行。 在这种情况下,由于我们正在处理向量,因此它应该不是问题,但这是需要注意的事情。
只要aprimes向量不改变(添加内容),它就不会重新分配。
只要它不重新分配,各种tprimes向量就不会四处移动。每个tprime在内存中都有自己的位置。每个线程将从不同的向量读取和写入。
因此,它是安全的。
- 具有引用成员的结构是否具有唯一的对象表示形式
- COM :是否可以查看是否存在对我的某个 COM 对象的进程外引用?我可以释放它吗?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 如果我们通过引用传递变量,则递归中使用的堆栈空间量是否为零?
- 是否可以跨 dll 边界返回常量引用/指向 std::vectors?
- C++中大多数/所有 setter 函数的参数是否应该写为常量引用?
- Java 中是否有类似于 C++ 中引用类型"&"的内容?
- <Base> <Derived> 具有相同原始指针共享引用的 shared_ptr 和 shared_ptr 实例是否计数?
- 存储对(可能)临时对象的引用是否合法,只要引用不比对象存活?
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 通过引用访问矢量元素是否会降低C++的空间复杂性?
- 对静态分配的子类对象进行静态分配的纯虚拟父类引用是否合法?
- 仅通过引用捕获的 lambda 表达式是否保证不会抛出?
- 形成对对象的引用是否构成访问?
- std::vector 是否有用于引用的复制构造函数?
- C++ 引用是否在需要时隐式转换为值?
- 如何检测两个文件条目是否引用与Qt相同的物理文件系统?
- 是否引用右值
- 在 c++ 中,知道路径是否引用文件夹或文件的最便宜的方法是什么?
- 测试一个东西是否引用了另一个东西