原子操作保证了资源访问的互斥性和访问时序
原子操作翻译过程中首先面临的一个挑战是原子指令的等价翻译
原子指令:
CAS指令
x86 平台有将近 20 条原子指令, 如
inc、xadd 原子操作以及 cmpxchg 比较并交换 (compare and swap, CAS) 指令
LL/SC 指令对
MIPS、ARM、Alpha 等平台并没有 CAS 指令, 其对应的是链接加载 (load linked, LL) 和条件存储(store conditional, SC) 指令组成的 LL/SC 指令对
CAS 原子指令的翻译方法
(1) 将源程序中所有的内存写操作转为原子写, 以保证访问内存数据的一致性. 但是这种做法对性能影响大
(2) 维持源程序逻辑, 利用 CAS 和 LL/SC 指令对进行功能的等价模拟,,即把LL/SC用CAS表示出来
从 LL/SC 到 CAS 翻译遇到的问题
正确性问题
但是方法二存在从 LL/SC 到 CAS 翻译的正确性问题
解决方法:提出基于内存事务解决多线程应用之间的数据竞争问题, 将元数据访问封装在一个事务性原子块内完成
ABA 问题
还可能会引发 ABA 问题
解决方法:
1.利用 Helper 函数软件模拟实现 LL/SC 锁指令翻译
2.无锁队列引用计数的内存保护方法, 只有内存引用节点计数值为 0 时才允许访问该内存
3.通过位图维护 Cache 行和哈希完整地址行检查来避免数据竞争并保证数据访问的原子性
4.利用插桩的方式维护一个非阻塞哈希表来记录更新内存, 保证了锁变量地址与被访问内存地址的一致性.
地址非对齐问题
x86 平台支持多种地址非对齐的原子操作,但译通常要求先将访存地址对齐,但在不同位宽的原子指令翻译时依旧可能会引发错误
.MIPS、ARM、Alpha 等平台要求 LL/SC 指令满足 32 位地址对齐
解决
利用 LL/SC 指令对模拟 CAS 指令
但是该方法基于软件模拟 CAS 指令, 可能会引发大量的冗余判断.