通过不同的线程填充std::vector



我需要在不同的线程上填充一个std::vector。

这是正确的代码吗?或者我应该为我的代码添加互斥?

void func(int i, std::vector<float>& vec)
{
vec[i] = i;
}
int main()
{
std::vector<float> vec(6);
std::list<std::thread> threads;
for (int i = 0; i < 6; i++)
{
threads.push_back(std::thread(func, i, std::ref(vec)));
}
for (auto iter = threads.begin(); iter != threads.end(); iter++)
{
(*iter).join();
}
}

我测试了我的代码,它运行良好。有陷阱吗?它是线程安全代码吗?

通过不同的线程获取std::矢量数据怎么样?

相关问题:
std::vector线程默认情况下是安全和并发的吗?为什么?。

它是线程安全的,因为您不修改向量大小,也不试图在不同的线程中写入相同的内存位置。

为了证明未来,这个答案适用于任何不深入链接的人:

  1. 这不是线程安全的only,因为他们使用的是[]运算符。它是线程安全的,因为每个线程都显式地修改内存中不同的位置。

  2. 如果所有线程都只使用[]读取相同的位置,那么这将是线程安全的。

  3. 如果所有线程都在同一个位置写入,那么使用[]并不能阻止它们相互干扰。

  4. 我认为如果这是生产代码,至少需要一条注释来描述为什么这是线程安全的。如果有人修改了这个函数,不确定有什么编译时的方法可以防止他们开枪自杀。


在第4点上,我们希望与该代码的未来用户沟通:

  1. 不,我们没有保护这个标准库容器,尽管这应该是你的本能反应,而且
  2. 是的,我们已经分析过了,它是安全的

简单的方法是在其中粘贴评论,但有一句话:

编译器不读取注释,我也不读取。
-Bjarne Stroustrup

我认为某种[[attributes]]应该是实现这一点的方法?尽管内置程序似乎不支持任何类型的线程安全检查。


Clang似乎提供了线程安全分析:

该分析仍在积极开发中,但已经足够成熟,可以部署在工业环境中。

假设您实现了其他需要std::mutex负责std::vector:的功能

std::mutex _mu;
std::vector<int> _vec GUARDED_BY(_mu);

那么您可以显式地添加NO_THREAD_SAFETY_ANALYSIS属性来关闭这一特定功能的安全检查。我认为最好将此与评论结合起来:

// I know this doesn't look safe but it is as long as
// the caller always launches it with different values of `i`
void foo(int i, std::vector<int>& vec) NO_THREAD_SAFETY_ANALYSIS;

GUARDED_BY的使用告诉我,在未来,您正在考虑线程安全性。NO_THREAD_SAFETY_ANALYSIS的使用表明,您已经确定可以使用此函数,尤其是当修改vector的其他函数未标记为NO_THREAD_SAFETY_ANALYSIS时。

是的这是线程安全的,因为您既不是从不同的线程写入向量对象本身,也不是写入向量底层数组中的同一对象。

构造向量时,为6个元素分配空间,并为int等pod类型填充零。这些元素被放置在向量拥有和管理的数组中,向量通过迭代器和operator []公开它们。

因此,当你编辑向量中的一个元素时,你不必编辑向量本身,所以你不必用互斥锁来保护向量。

如果要修改向量本身或不同线程中的同一元素,则需要一个互斥对象。

最新更新