C++ 在x86上,bool读/写操作可以不是原子的吗?

C++ 在x86上,bool读/写操作可以不是原子的吗?,c++,x86,boolean,atomic,C++,X86,Boolean,Atomic,假设我们有两个线程,一个在循环中读取bool,另一个可以在特定时间切换它。我个人认为这应该是原子的,因为C++中的代码> siZeof(BoOL)< /C> >是1字节,你不读/写字节,但我想100%肯定。< /P> 那么是还是不是 编辑: 同样,供将来参考,这是否也适用于int?x86仅保证字大小的字对齐读写。它不保证任何其他操作,除非显式原子化。另外,当然,你必须说服你的编译器在第一时间实际执行相关的读写操作。这取决于你所说的“原子”这个词的真正含义 你的意思是“最终值将一次更新”(是的,在

假设我们有两个线程,一个在循环中读取bool,另一个可以在特定时间切换它。我个人认为这应该是原子的,因为C++中的代码> siZeof(BoOL)< /C> >是1字节,你不读/写字节,但我想100%肯定。< /P> 那么是还是不是

编辑


同样,供将来参考,这是否也适用于
int

x86仅保证字大小的字对齐读写。它不保证任何其他操作,除非显式原子化。另外,当然,你必须说服你的编译器在第一时间实际执行相关的读写操作。

这取决于你所说的“原子”这个词的真正含义


你的意思是“最终值将一次更新”(是的,在x86上,字节值和任何至少64位的正确对齐值都是有保证的),还是“如果我将其设置为true(或false),在我设置之后,没有其他线程会读到不同的值”(这不是很确定-你需要一个“锁”前缀以保证)

C++11中的“原子”类型解决了三个不同的问题:

撕:读或写涉及多个总线周期,并且在操作的中间出现线程切换;这可能会产生不正确的值

  • 缓存一致性:来自一个线程的写入更新其处理器的缓存,但不更新全局内存;从不同线程读取的数据读取全局内存,在另一个处理器的缓存中看不到更新的值

  • 编译器优化:编译器在不从另一个线程访问值的假设下,对读写顺序进行洗牌,从而导致混乱


  • 使用
    std::atomic
    可确保正确处理这三个问题。不使用
    std::atomic
    只会让您猜测,充其量只能使用不可移植的代码。

    底层架构的字数不是既原子又不尽可能低的效率吗?建议它是非原子的。顺便说一句,我不知道标准中有任何要求要求
    sizeof(bool)
    @LightnessRacesinOrbit:5.3.3甚至有关于如何定义实现的说明。是的,sizeof(bool)是实现定义的。我曾经研究过sizeof(bool)==4的体系结构。“如果我将其设置为true(或false),那么在我设置之后,其他线程将不会读取不同的值”。我认为问题很清楚。后一种解释与原子性无关。@jberryman:问题在于缓存以及编译器优化内存读取。
    b=false不保证所有其他线程在下一个
    if(b)…
    情况下都会检测到
    b
    为false。这要求编译器没有优化对
    b
    tmp=b;的访问。。。if(tmp).
    [其中
    tmp
    是一个寄存器]。根据线程中的代码,编译器会在某些情况下执行此操作。在我设置后,其他线程不会读取不同的值-
    mfence
    lock
    前缀仅用于确定“after”的含义。所有x86系统上的内存都是一致的,因此在store指令最终提交到L1d缓存之后,其他线程都无法读取旧值。您只需要使用屏障来实现seq cst存储,并确保在存储全局可见之前,该线程不会执行任何其他加载。它肯定会很快在全球范围内独树一帜。TL:DR:barrier不会显式刷新或写回缓存,它只会暂停此线程,直到值从存储缓冲区提交到此核心的L1d缓存(从而全局可见)。“如果我将其设置为true(或false),那么在我设置它之后,其他线程将不会读取不同的值”(这不是很确定-您需要一个“锁”前缀以保证)——bool可以有任何硬件实现,另一个线程可以读取任何,甚至可能是bool的“部分”状态。但读取的值被解释为真或假。所以不能有任何“不同的价值”。从这个意义上说,阅读布尔总是“原子的”——我们总是得到正确或错误,从来没有什么不同。锁定只需要在rmw操作的情况下,或者当我们需要在这个bool和其他mem之间排序时,难道在运行时不存在CPU指令(或内存访问)重新排序吗?编译器可以对加载和存储进行重新排序,但CPU也可以这样做。@RomanKruglov:在x86上,只有StoreLoad重新排序是可能的(),因此除了阻止编译时重新排序之外,只有seq cst存储需要额外的排序。(例如,
    mov
    +
    mfence
    ,或者更好的
    xchg
    来实现seq-cst存储。)一般来说,在其他ISA上,是的负载、存储和RMW可能需要额外的屏障,如果它们没有使用
    mou-released
    。缓存一致性不是问题;正常系统已经一致(使用MESI或变体)。原子的
    实际上需要做的是阻止编译器在寄存器中保留值,而寄存器是线程私有的。(). 另外,对于x86上的seq cst存储,在以后的加载可以运行之前,暂停当前线程,直到存储变得全局可见(例如,通过使用
    xchg
    mfence
    )。全局可见性将自行发生,但可能在以后加载之后发生。另请参阅,另请参阅:手动一致性。C++是围绕着共享共享内存的假设而设计的,所以你需要做的就是确保存储或负载实际上在ASM中发生,而不是在登记器中保持一个值。在一个假设非相干共享内存的机器上,每一个同步都必须刷新所有的(或者需要很多跟踪),但是我不知道任何非相干共享线程的标准线程的C++实现。