如果我有比较和交换操作
void push(const T& data){
node * newNode = new node{data};
newNode->next = head.load();
while(!head.compare_exchange_weak(newNode->next, newNode));
}这样的操作是否会使指针为head、newNode->next和newNode的高速缓存线锁定正在执行它的线程?
P.S.当然,如果它们存储在不同的高速缓存线中。
发布于 2021-08-06 15:42:32
这依赖于目标架构。实际上,高速缓存线锁定是一种依赖于目标平台的策略,因此C++规范中没有对此进行描述(该标准只说读-修改-写是原子完成的)。
在x86平台上,当数据类型的大小很小时(在64位系统上通常是64位的<= ),编译器通常会执行use the lock cmpxchg指令。在这样的上下文中,指令始终接受参数中的内存操作数和寄存器操作数。比较的值是存储在寄存器rax/eax/ax/ah.中的值因此,expected和desired直接存储在寄存器中,或者在操作之前从内存加载。只有存储原子值的高速缓存线才能被锁定。
此外,您还可以找到有关该指令的更多信息here:
此指令可与LOCK前缀一起使用,以允许自动执行指令。为了简化与处理器总线的接口,目标操作数接收写入周期,而不考虑比较结果。如果比较失败,则写回目标操作数;否则,将源操作数写回目标。(处理器永远不会在不产生锁定写入的情况下产生锁定读取。)
因此,原子操作可以在lock cmpxchg指令的时间内临时锁定高速缓存线。
正如@Frank所指出的,在宽类型上工作的原子CAS操作可能会产生不同的汇编指令。在这种情况下,可以使用锁来确保原子性。可以使用函数is_lock_free()来检查某个特定情况下是否使用了锁。
有关x86指令和x86锁前缀的更多信息,请阅读:
https://stackoverflow.com/questions/68673894
复制相似问题