原子操作跨进程的工作方式与跨线程的工作方式相同吗?

时间:2009-10-18 17:43:55

标签: multithreading scheduling atomic shared-memory lock-free

显然,原子操作可以确保不同的线程不会破坏某个值。但是当使用共享内存时,这是否仍然适用于进程?即使操作系统恰好安排进程在不同的内核上运行?或者跨越不同的不同CPU?

编辑:另外,如果它不安全,即使在Linux这样的操作系统上也不安全,因为从调度程序的角度来看,进程和线程是相同的?

1 个答案:

答案 0 :(得分:3)

tl; dr:阅读原子操作文档中的细则。有些将是原子设计,但可能会跳过某些变量类型。但是,一般情况下,原子操作将保持其在不同进程之间的契约,就像在线程之间一样。

原子操作实际上只能确保在两个实体同时调用时不会出现不一致的状态。例如,由同一个整数上的两个不同线程或进程调用的原子增量将始终如下:

  1. x =初始值(为了讨论而为零)
  2. 实体A递增x并将结果返回给自身:result = x = 1。
  3. 实体B递增x并将结果返回给自身:result = x = 2。
  4. 其中A和B表示进行调用的第一个和第二个线程或进程。

    由于竞争条件,对地址空间的写入不完整等原因,非原子操作可能导致不一致或通常是疯狂的结果。例如,您可以很容易地看到:

    1. x =初始值= 0。
    2. 实体A调用x = x + 1.要评估x + 1,A检查x(零)的值并加1。
    3. 实体B调用x = x + 1.要评估x + 1,B检查x的值(仍为零)并加1。
    4. 实体B(通过运气)首先完成并将x + 1 = 1(步骤3)的结果分配给x。 x现在是1。
    5. 实体A完成第二个并将x + 1 = 1(步骤2)的结果分配给x。 x现在是1。
    6. 注意竞赛条件,因为实体B比赛过去A并首先完成表达式。

      现在想象一下,如果x是64位双精度,则无法确保具有原子赋值。在这种情况下,你可以很容易地看到这样的东西:

      1. 64位双x = 0.
      2. 实体A尝试将0x1122334455667788分配给x。首先分配前32位,将x与0x1122334400000000分开。
      3. 实体B参加比赛并将0xffeeddccbbaa9988分配给x。偶然的是,两个32位的一半都被更新,x现在是= 0xffeeddccbbaa9988。
      4. 实体A使用后半部分完成其赋值,x现在为= 0xffeeddcc55667788。
      5. 这些非原子分配是您必须诊断的一些最可怕的并发错误。