Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading CAS指令如何保证原子性_Multithreading_Assembly_Atomic - Fatal编程技术网

Multithreading CAS指令如何保证原子性

Multithreading CAS指令如何保证原子性,multithreading,assembly,atomic,Multithreading,Assembly,Atomic,根据中国科学院的研究,中国科学院的工作如下: function cas(p : pointer to int, old : int, new : int) returns bool { if *p ≠ old { return false } *p ← new return true } 好吧,在我看来,如果几个处理器试图用相同的参数执行CAS指令,那么在同一时间可能会有几次写入尝试,所以无论如何这样做都不安全 我错在哪里?如果你读了维基,它会说

根据中国科学院的研究,中国科学院的工作如下:

function cas(p : pointer to int, old : int, new : int) returns bool {
    if *p ≠ old {
        return false
    }
    *p ← new
    return true
}
好吧,在我看来,如果几个处理器试图用相同的参数执行CAS指令,那么在同一时间可能会有几次写入尝试,所以无论如何这样做都不安全


我错在哪里?

如果你读了维基,它会说CAS是你发布的代码的“以下伪代码的原子版本”。原子意味着代码将在没有其他线程中断的情况下执行。因此,即使多个线程试图使用相同的参数同时执行此代码(如您所建议的),其中只有一个线程将返回true,因为实际上它们不会同时执行,因为原子性要求它们独立运行


由于您提到“x86不能保证非对齐DWORD写入的原子性”,这也不是一个问题,因为cas函数的原子属性。

同时来自多个核的原子读比较写指令确实会相互冲突,但这取决于硬件。在现代CPU中是真实存在的,它提供了一定程度的公平性,因此在
lock cmpxchg
上旋转的一个线程不能完全阻止其他线程执行相同的操作。(尽管这是一个糟糕的设计:最好在获取负载上旋转,并且只有在CAS成功时才进行)

无法保证它们发生的顺序,这就是为什么需要仔细设计算法,以便正确性只取决于比较和交换是原子的。(这是一个常见的陷阱)


顺便说一句,整个伪代码块作为单个原子操作发生。对于硬件来说,将读-比较-写或读-修改-写作为单个原子操作进行要比存储困难得多,而MESIF/MOESI可以很好地处理存储

你确定吗?我认为这样做是不安全的,因为,例如,x86不能保证非对齐DWORD写入的原子性

lock cmpxchg
使操作原子化,而不考虑对齐方式。对于未对齐的缓存线,它可能会慢得多,尤其是在缓存线拆分时,在这种情况下,仅对单个缓存线进行原子化修改是不够的


另请参见我在其中解释的操作原子化的含义。

只要清楚谁赢了,同时进行多个写入操作就不是问题。你们可能会想,为了安全起见,需要额外的处理。但是在ints的情况下,这没有问题。@Voo“同时进行多个写入不是问题”——你确定吗?我认为这样做是不安全的,因为,例如,x86不能保证非对齐数据的写入原子性,或者仅仅有
CMPXCHG
指令还不够?我应该用
LOCK
前缀来标记它吗?@frozenhart:如果你想让它成为原子的,你需要
LOCK
lock
对于带有内存操作数的
xchg
是隐式的,但对于任何其他指令都是隐式的。因此,
CAS
本身不足以提供原子性,因此我们也应该在它前面加上
lock
前缀。那么,像
CMPXCHG
这样的指令有什么意义呢?仅仅因为我们一次只能锁定一条指令?使用诸如没有前缀的指令(如
cmpxchg
)至少在两种情况下是有用的:(1)在单CPU系统上,可以删除锁定前缀,至少在诸如DMA或其他在同一宏上竞争的非CPU代理等模糊情况之外。单CPU构建(即CONFIG_SMP=n)就是一个很好的例子-大多数原子操作隐藏在宏后面,当SMP被禁用时,宏可以简单地省略
lock
前缀。如果没有
lock
前缀,在遇到中断时仍然可以使用指令原子性,这正是您所需要的。@BeeOnRope:这一点很好。Linux实际上比这走得更远:在UP系统上引导SMP内核实际上是将
lock
前缀补丁到
0x90
NOP中所有在UP上不需要它的地方。如果禁用抢占,它还会修补一些锁定/解锁代码。(IIRC,内核日志消息是
修补SMP备选方案
或其他内容)。关于在教学水平上具有原子性的极好观点;我可以看出非锁定的CMPXCHG实际上是如何有用的,就像这样。