C#数组的线程安全性

13

拥有两个不同的线程:

  • 一个从C#数组中读取(例如,从第一个位置开始)
  • 另一个将数据写入到相同的C#数组但是写入到不同的位置(例如,写入到最后一个位置)

这种情况下是否线程安全?
(我指的是在没有锁定读取或写入的情况下)

3个回答

8

这个特定的情况是安全的。

读写数组的不同部分不会干扰其他操作。

然而,如果读写同一位置,则可能会出现问题,具体取决于元素类型和元素大小。


1
只要这些项在不同的CPU字中, - Stewart
+1 从来没想过这是线程安全的,但我理解为什么是这样的。谢谢! - Will Marcouiller
在使用无锁算法时,重要的是要考虑到你所认为的“相同位置”并不等同于CPU所认为的“相同位置”。CPU对内存的视图与像C语言这样的语言所给出的视图非常不同,其中字节占据地址。在某些CPU架构(特别是ARM、Power)上,在某些数据类型上,即使这样做也可能不安全。 - Stewart
没错,我应该让它更清晰明了。我默认它是一个相当大的数组,所以第一个和最后一个项目应该是安全的,但是在内存中一起的项目可能会成为问题。 - Lasse V. Karlsen

7

我不确定这样做是否保证安全。想象一下你有一个byte[]数组,这些字节在内存中紧密地排列着。现在,如果你修改这些字节,编译器可能会合并一些写操作以执行32位大小的读取修改写入操作。在某些CPU上,例如ARM,这是编译器唯一的一种内存修改指令。如果你一次要修改多个字节,这将非常方便。CPU也可以做同样的事情,而且可以在你不知道的情况下重新排序。面对这种优化,一个线程读取相邻内存时可能会看到部分修改。通常情况下你看不到这种效果,因为堆分配器很好心地给你分配了至少按字对齐的内存。


1
+1:在我看来,这是最好的答案。 总是最好对无锁线程习语持怀疑态度。 即使线程使用不同的数组位置,我也可以想到各种可能导致问题的内存屏障问题。 在问题中提供的信息还不足以给出明确的答案。 - Brian Gideon

6
长话短说:是的。只要它们分别到达两个不同的位置,这就是一个安全的操作。
之前有一个关于此问题的讨论,如果您感兴趣可以查看一下:https://dev59.com/_nM_5IYBdhLWcg3wQQld

+1 从未想过这是线程安全的,但我理解为什么。谢谢! - Will Marcouiller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接