我是c ++中std :: atomic的新手,试图了解ARM处理器下比较和交换操作的实现。我在Linux上使用gcc。
当我查看汇编代码时
mcr p15, 0, r0, c7, c10, 5
.L41:
ldrexb r3, [r2]
cmp r3, r1
bne .L42
strexb ip, r0, [r2]
cmp ip, #0
bne .L41
.L42:
mcr p15, 0, r0, c7, c10, 5
我的理解是
我的问题是
ldrex标记虚拟地址。作为专有地址还是实际地址?
如果进程P1将虚拟地址标记为互斥,并且进程切换到P2,则该虚拟地址将被转换为P2。在P2中可以访问?如果P2还对同一地址执行ldrex,将会发生什么情况。
如果进程P1将物理地址标记为互斥,并且发生进程切换,则当P1恢复时,由于现在数据没有可能驻留在物理内存中的其他位置,分页。
我试图理解这一点,因为,我想对多个进程访问的共享内存位置进行比较和交换。
我的c ++函数看起来像
std::atomic<bool> *flag;
flag = (std::atomic<bool> *) (shm_ptr);
bool temp = false ;
while(!std::atomic_compare_exchange_strong((flag),&temp,true))
{
std::this_thread::yield();
}
// update shared memory
std::atomic_store((flag), false);
答案 0 :(得分:1)
是的,在ARM的所有主流C ++实现中,在不同进程映射的共享内存上使用无锁std::atomic<T>
是安全的。
但是非无锁原子将不起作用,因为不同的进程不会共享同一张锁表。
strex
完成之前的中断将导致失败。您不必担心内核代码会在ldrex和strex之间更改页表。
在同一个或另一个CPU上发生中断后,在中间恢复此代码将意味着strex
完全失败,因为它不是作为由ldrex
启动的“事务”的一部分而执行的。
原子性在ARM上以及在所有实现C ++ 11无锁原子的普通主流系统上都是无地址的。
如果不同内核上的两个线程/进程将相同的物理页面映射到不同的虚拟地址,则一切仍然有效。 C ++ 11标准明确建议,对于无锁std::atomic<T>
,实现应以这种方式工作。 (它并没有要求它,因为那样的话,它就必须定义一个进程是什么,并具有重新映射虚拟内存的功能。)
这几乎是Are lock-free atomics address-free in practice?的副本。有关标准和更多详细信息的引用,请参见。
现代计算机系统确保其缓存不存在别名同名/同义词问题,因为这通常会导致一致性问题,而不仅仅是原子RMW。有时,这需要OS内核的配合(例如,如果一个缓存索引位来自页码而不是地址的一页内偏移量,则页面着色),但是通常,缓存的行为是物理的。
(某些早期的CPU,例如早期的MIPS,有时确实使用了虚拟寻址的L1数据高速缓存,但是在支持多个CPU的系统AFAIK上并没有做到这一点。)