当使用共享内存时,每个进程可以将共享区域映射到其各自地址空间的不同区域。这意味着当在共享区域中存储指针时,您需要将它们存储为偏移量共享区域的开始。不幸的是,这使原子指令的使用变得复杂(例如,如果您尝试编写一个无锁算法)。例如,假设共享内存中有一堆引用计数节点,由单个编写器创建。写入器定期自动更新指针“p”以指向具有正引用计数的有效节点。读者希望以原子方式写入“p”,因为它指向第一个元素是引用计数的节点(结构)的开头。由于 p 始终指向有效节点,因此增加引用计数是安全的,并且可以安全地取消引用“p”并访问其他成员。然而,这一切仅当所有内容都位于同一地址空间时才有效。如果节点和“p”指针存储在共享内存中,则客户端会遇到竞争条件:
- x = 读取 p
- y = x + 偏移量
- 在 y 处增加重新计数
在步骤 2 期间,p 可能会发生变化,并且 x 可能不再指向有效节点。我能想到的唯一解决方法是以某种方式强制所有进程就共享内存的映射位置达成一致,以便真正的指针而不是偏移量可以存储在 mmap 区域中。有什么办法可以做到这一点吗?我在 mmap 文档中看到 MAP_FIXED,但我不知道如何选择一个安全的地址。
编辑:在 x86 上使用内联汇编和“锁定”前缀也许可以构建“增量 ptr X,偏移 Y 值 Z”?其他架构上的等效选项?没有写过很多汇编,不知道需要的指令是否存在。
在低级别上,x86 原子指令可以一次执行所有此树步骤:
- x = 读取 p
- y = x + 偏移增量
- y 处的重新计数
//
mov edi, Destination
mov edx, DataOffset
mov ecx, NewData
@Repeat:
mov eax, [edi + edx] //load OldData
//Here you can also increment eax and save to [edi + edx]
lock cmpxchg dword ptr [edi + edx], ecx
jnz @Repeat
//
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)