<vector> 在不同位置读/写是线程安全的吗?

Posted

技术标签:

【中文标题】<vector> 在不同位置读/写是线程安全的吗?【英文标题】:is < vector > threadsafe for read/write at different locations? 【发布时间】:2011-06-23 13:52:03 【问题描述】:

我猜这是一个初学者的问题,但我找不到这个特定问题的答案:

我有一个大小为 10 且类型为 int 的标准 (c++) 向量 v。

让线程改变所有偶数位置是否安全(v.at(0) = x; v.at(2) = y; 等等) 和另一个线程同时更改奇数位置的所有值(v.at(1) = a; v.at(3)=b;等)?

所以,在这 2 个线程的生命周期内,大小没有变化,没有 push_back() 等。

如果不安全,使用数组会是更好的方法吗?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

vector 不提供任何线程安全保证,因此从技术上讲,答案是否定的。

在实践中,您应该能够侥幸成功...直到有人(可能是您)在程序的某个角落进行了微小的更改,然后一切都崩溃了。在任何重要的程序中这样做我都不会感到舒服。

【讨论】:

+1 用于避免在此应用交付后不眠之夜,更糟糕的是,它得到了增强/维护:( 感谢您的回答。我明白你的意思......不过:你将如何解决这个问题?因为这个想法是将一个相当大的变量网格划分为多个部分以共享计算时间。锁定整个网格/矢量会减慢速度 @Benthebear:也许从相反的角度......分部分生成网格,不加锁地独立处理每个部分,最后合并结果。这行得通吗? 它可以。不过,事情将很难阅读。回到最初的问题,数组 [] 在这里有什么不同吗? @Benthebear:数组可以使实际的“它会起作用”的判断在学术上也站得住脚;如果失去便利并没有伤害到你,那就继续吧。但它本身并不能解决“将来可能会中断”的问题。您可能需要考虑将数组的块作为特制的迭代器传递;这样,数组分区对您的工作人员来说将是不透明的(没有发生事故的机会),并且您只会将所有这些责任浓缩到一段代码中(创建所有迭代器)。应该非常易于维护。【参考方案2】:

来自 MSDN:Thread Safety in the Standard C++ Library

对于同一个对象的读取,该对象对于读取是线程安全的:

当其他线程上没有作者时,一次从一个线程。 当其他线程上没有作者时,一次来自多个线程。

对于同一个对象的写入,当其他线程上没有读取器时,该对象是线程安全的,可以从一个线程写入

对于同一个类的不同对象的读取,对象是线程安全的读取:

一次来自一个线程。 当其他线程上没有作者时,一次从一个线程。 一次来自多个线程。 当其他线程上没有作者时,一次来自多个线程。

对于同一类的不同对象的写入,对象是线程安全的:

当其他线程上没有读者时从一个线程。 来自许多线程。

因此,从以上所述,理论上,不,它不会是线程安全的

【讨论】:

【参考方案3】:

理论上:不会。

实际上:是(根据所有众所周知的 STL 的实现方式)

【讨论】:

对于std::vector&lt;bool&gt;,这实际上应该是“否”。我只是花了几个小时调试一个疯狂的错误,其中我的代码与问题中的代码相似,除了它是std::vector&lt;bool&gt;。出于某种原因,std::vector&lt;bool&gt; 是一个位集,每个元素一个位。由于处理器一次加载8位或更多位的字,它无法分别处理v[i]v[i+1],因此存在严重问题。【参考方案4】:

这取决于机器。如果您有一个vector&lt;char&gt;,处理器可能无法以单独的单词加载 v[i] 和 v[i+1]。您可能会遇到缓存一致性问题。

编译器和处理器都可能重新排序指令,即使上述情况不适用,这也可能会破坏您的程序。 This is why C++0x has a memory model.

【讨论】:

【参考方案5】:

您描述的场景将是安全的 - 您可以有效地操作固定大小数组的各个元素(因为 vector 在这些操作期间大小不会改变),因此您首先不需要任何额外的同步除非您从多个线程中操作任何元素(不是您的情况)。

【讨论】:

以上是关于<vector> 在不同位置读/写是线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章

list和vector有啥区别

集合ArrayList和Vector的区别?

C++STL二维vector指定位置排序

scanf函数读入整数后接着读字符串的换行符残余问题

C++读CSV

模板 超级读优