根据Wiki,CAS做这样的事情:
function cas(p : pointer to int, old : int, new : int) returns bool { if *p ≠ old { return false } *p ← new return true }
嗯,在我看来,如果多个处理器将尝试使用相同的参数执行CAS指令,则可能会同时进行多个写入尝试,因此无论如何这样做都不安全。我哪里错了?
8qgya5xd1#
来自多个内核的原子读-比较-写指令(在同一高速缓存线上)* 确实 * 会相互竞争,但这取决于硬件来解决。Hardware arbitration of atomic RMW instructions是现代CPU中的一个真实的的东西,它提供了一定程度的公平性,因此lock cmpxchg上的一个线程不会完全阻止其他线程执行相同的操作。(尽管这是一个糟糕的设计,除非your retry could succeed without waiting让另一个线程修改任何东西,例如,实现fetch_oror similar的重试循环可以使用expected的更新值再次尝试。但是,如果等待锁或标志更改,在初始CAS失败后,it's better将在获取或释放负载上旋转,并且仅在CAS可能成功时执行CAS。)没有人能保证它们发生的顺序,这就是为什么你需要仔细设计你的算法,以便正确性只依赖于原子的比较和交换。(ABA problem是一个常见的陷阱)。顺便说一句,整个伪代码块作为单个原子操作发生。对于硬件来说,使读-比较-写或读-修改-写作为单个原子操作发生比仅仅存储要困难得多,MESIF/MOESI处理得很好。您确定吗?我认为这样做是不安全的,因为,例如,x86不能保证对非对齐DWORD的写操作的原子性lock cmpxchg使操作原子化,而不管是否对齐。对于未对齐的操作,它可能会慢很多,尤其是在高速缓存行拆分时,原子化修改单个高速缓存行是不够的。另请参见x86上的原子性,我在其中解释了原子操作的含义。
lock cmpxchg
fetch_or
expected
nvbavucw2#
如果你读过wiki,它会说CAS是你发布的代码的“以下伪代码的原子版本”。原子意味着代码将在没有其他线程中断的情况下执行。因此,即使多个线程试图使用相同的参数同时执行这段代码(就像你建议的那样)只有一个返回true,因为实际上它们不会同时执行,因为原子性要求它们独立运行。由于您提到“x86不保证对非对齐DWORD的写入的原子性”,这在这里也不是问题,因为cas函数的原子属性。
2条答案
按热度按时间8qgya5xd1#
来自多个内核的原子读-比较-写指令(在同一高速缓存线上)* 确实 * 会相互竞争,但这取决于硬件来解决。Hardware arbitration of atomic RMW instructions是现代CPU中的一个真实的的东西,它提供了一定程度的公平性,因此
lock cmpxchg
上的一个线程不会完全阻止其他线程执行相同的操作。(尽管这是一个糟糕的设计,除非your retry could succeed without waiting让另一个线程修改任何东西,例如,实现
fetch_or
or similar的重试循环可以使用expected
的更新值再次尝试。但是,如果等待锁或标志更改,在初始CAS失败后,it's better将在获取或释放负载上旋转,并且仅在CAS可能成功时执行CAS。)没有人能保证它们发生的顺序,这就是为什么你需要仔细设计你的算法,以便正确性只依赖于原子的比较和交换。(ABA problem是一个常见的陷阱)。
顺便说一句,整个伪代码块作为单个原子操作发生。对于硬件来说,使读-比较-写或读-修改-写作为单个原子操作发生比仅仅存储要困难得多,MESIF/MOESI处理得很好。
您确定吗?我认为这样做是不安全的,因为,例如,x86不能保证对非对齐DWORD的写操作的原子性
lock cmpxchg
使操作原子化,而不管是否对齐。对于未对齐的操作,它可能会慢很多,尤其是在高速缓存行拆分时,原子化修改单个高速缓存行是不够的。另请参见x86上的原子性,我在其中解释了原子操作的含义。
nvbavucw2#
如果你读过wiki,它会说CAS是你发布的代码的“以下伪代码的原子版本”。原子意味着代码将在没有其他线程中断的情况下执行。因此,即使多个线程试图使用相同的参数同时执行这段代码(就像你建议的那样)只有一个返回true,因为实际上它们不会同时执行,因为原子性要求它们独立运行。
由于您提到“x86不保证对非对齐DWORD的写入的原子性”,这在这里也不是问题,因为cas函数的原子属性。