线程可以混合写入值吗?

问题描述:

作为一个业余爱好项目,我正在用垃圾收集来创建一种编程语言。 该语言将被编译为(最好是可移植的)C++并支持线程。线程可以混合写入值吗?

现在的问题是: 支持两个线程“同时”将不同的值写入同一个(指针大小和对齐的)内存位置。 那么是否有可能让任何线程读取两个值之间的混合?

例如在32位平台上:

线程1条写道:AAAAAAAA

线程2条写道:BBBBBBBB

将任何线程总是读AAAAAAAA或BBBBBBBB也可以读取AAAABBBB或其他一些两者之间的“混合”? 我不关心订购和最终价值。重要的是,从该位置不能读取任何无效值。

我意识到这可能取决于平台,C++可能不会提供任何承诺。 对于某些平台会有保证吗?是否需要使用内联汇编器来实现? PS:我相信std :: atomic会做出这样的保证,但是我认为使用所有加载/存储操作来处理对象引用会有很大的开销。

+1

如果您正在编写以空字符结尾的字符串并且尚未附加终止字符,该怎么办?你可能不想混合读写。 – AndyG

+2

作为一个语言设计者,它定义了数据竞赛发生时会发生的事情。你可以决定一个实现必须以某种方式处理它(限制性能),或者你可以决定底层硬件决定发生了什么(而不是平*立),或者任何事情都是可能的(很难编程在)。问我们你的语言如何在某种情况下表现得没有意义。 – nwp

+0

我在问C++的行为,因为我打算编译为C++。我知道C/C++有很多未定义的行为,所以我的问题是如何在C++中实现“从不读取无效指针”的保证。 – LaZe

C++没有这样的保证,它取决于硬件。 典型的硬件/处理器,如Arm,x86,amd64,只要写入是32位对齐的,那么32位读写操作将是原子的。

每次读/写32位一个字节(比如strcpy,memcpy等),所有的注单都关闭 - 很大程度上取决于这些函数的实现(它们倾向于获得很多优化)。

当存在多个内存位置时,它在某些平台上变得更加复杂。

说你有

extern int32 a; 
extern int32 b; 

a = 0x12345678; 
b = 0x87654321; 

现在,单独,A和B是由线程1写入原子,但观察员,线程2,可以 “看到” A.

前b变动的价值

这可能由于硬件和软件而发生。 软件(C++编译器/优化器)可能会重新排列代码,如果它认为它会更好。 (或者,编译器甚至可能避免在某些情况下将值写入a和b)。

硬件还可以在运行时重新安排内存读/写 - 当thread1和thread2在不同内核上运行时可见,并且直到core1执行某些操作才能将内部内存管道与系统其余部分同步,core2可能会看到有些不同。对于这些优化,Ia64非常积极。 X86并没有太多(因为它会打破我假设的太多遗留代码)。

在C/C++中,“volatile”基本上可以让你告诉编译器在这个变量周围进行优化的时候不那么积极 - 尽管它确实取决于实现。通常这意味着编译器不会优化读/写易失变量,并且通常不会重新排列对它们的访问。

这不会改变处理器在运行时可能会发生的情况。为此,您需要使用特殊的“内存障碍”内隐/操作。 这些细节很复杂,通常隐藏在诸如“原子”之类的东西之后。噢,也是,大多数系统都有神奇的内存 - 某些地址由硬件保留用于特殊目的。通常情况下,除非你正在编写设备驱动程序,否则不会遇到这种情况

+0

嗨,你好,谢谢你阐述这个问题。 – LaZe