访问工作线程的 lambda 中捕获的向量列表中元素的引用时是不是需要互斥锁?
Posted
技术标签:
【中文标题】访问工作线程的 lambda 中捕获的向量列表中元素的引用时是不是需要互斥锁?【英文标题】:Is a mutex required when accessing references for elements in a list of vectors captured in a lambda for a worker thread?访问工作线程的 lambda 中捕获的向量列表中元素的引用时是否需要互斥锁? 【发布时间】:2019-07-17 18:07:53 【问题描述】:我有以下代码:
#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;
我在每个线程中使用的 lambdas 的向量 aprimes 列表中捕获对每个向量 (tprimes) 的引用。这次捕获安全吗?我应该在这里使用互斥锁或其他访问方法吗?代码确实有效,但我不确定以后是否会失败。
【问题讨论】:
为什么irange
上的这个复杂的 for 循环?只是为了复杂化?
@Slava 因为我更喜欢它,而且我可以做这样有趣的事情:for(const unsigned cpu: boost::irange(cpus)) 以进一步表明应该如何使用该值的意图。我真的应该在这篇文章的代码中使用它来对其他开发人员说“嘿,不要乱用这个索引,嗯,凯?”。还有,因为我更喜欢。我很喜欢。此外 ++i 是 1990 年代... ;-)
我不是说使用旧的好循环。我的观点是你过于复杂简单的事情。循环的前 2 行可以替换为:for( vector<uint64_t>& tprimes : aprimes ) ...
甚至 for ( auto &tprimes : aprimes ) ...
@Slava 我将此代码从工作代码中提取出来,以询问有关我如何引用 aprimes 列表中的向量的具体问题。我实际上在 lambda 中使用了 cpu 变量。这未显示,因为它与问题无关。是的,循环遍历 aprimes 向量也是一个不错的解决方案。
【参考方案1】:
是的,这是安全的。当我们谈论数据竞争和未定义的行为时,我们谈论的是多个线程修改同一个共享对象。在你的情况下,你没有这个。 aprimes
的每个元素都是它自己的不同对象,因此每个工作线程都在处理一个只有它正在访问的对象。即使它们都恰好在aprimes
内部,只要您不修改aprimes
,也不会改变这一点。在这种情况下,它就像是一个接一个地声明了一堆向量。
唯一需要注意的是您的主线程不允许修改aprimes
,也不允许修改aprimes
中的任何元素。如果这样做,那么您将有多个线程在没有同步的情况下写入共享对象,这是一种数据竞争和未定义的行为。
请注意,这样做时可能发生的一件事是false sharing。如果您有一个带有 4 个元素的 vector<int>
,并且每个线程都获得一个整数,那么即使没有线程共享该对象,它们也会共享该对象所在的缓存行。这会导致 CPU 不断地拥有在更新其中一个整数时同步 CPU 缓存,因为它只能在缓存行级别上工作。这将有效地使程序像没有线程一样运行,因为所有 4 个线程都不能同时修改缓存行。在这种情况下,因为我们正在处理向量,所以这应该不是问题,但需要注意。
【讨论】:
【参考方案2】:只要 aprimes 向量不改变(添加东西),它就不会重新分配。
只要不重新分配,各种 tprimes 向量就不会移动。每个 tprimes 在内存中都有自己的位置。每个线程将从/向不同的向量读取和写入。
因此,它是安全的。
【讨论】:
以上是关于访问工作线程的 lambda 中捕获的向量列表中元素的引用时是不是需要互斥锁?的主要内容,如果未能解决你的问题,请参考以下文章