我需要在不同的线程上填充一个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线程默认情况下是安全和并发的吗?为什么?。
它是线程安全的,因为您不修改向量大小,也不试图在不同的线程中写入相同的内存位置。
为了证明未来,这个答案适用于任何不深入链接的人:
-
这不是线程安全的only,因为他们使用的是
[]
运算符。它是线程安全的,因为每个线程都显式地修改内存中不同的位置。 -
如果所有线程都只使用
[]
读取相同的位置,那么这将是线程安全的。 -
如果所有线程都在同一个位置写入,那么使用
[]
并不能阻止它们相互干扰。 -
我认为如果这是生产代码,至少需要一条注释来描述为什么这是线程安全的。如果有人修改了这个函数,不确定有什么编译时的方法可以防止他们开枪自杀。
在第4点上,我们希望与该代码的未来用户沟通:
- 不,我们没有保护这个标准库容器,尽管这应该是你的本能反应,而且
- 是的,我们已经分析过了,它是安全的
简单的方法是在其中粘贴评论,但有一句话:
编译器不读取注释,我也不读取。
-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 []
公开它们。
因此,当你编辑向量中的一个元素时,你不必编辑向量本身,所以你不必用互斥锁来保护向量。
如果要修改向量本身或不同线程中的同一元素,则需要一个互斥对象。