在ARM多核处理器系统中,原子事务是实现并发控制的基础设施。所谓原子事务,指的是一个不可分割的操作序列,要么全部执行成功,要么完全不执行,不存在中间状态。这种特性对于实现多核间的数据同步至关重要。
ARM互连协议定义了三种基本原子事务类型:
带数据返回的原子操作:
不带数据返回的原子操作:
在从节点执行的原子操作:
关键提示:AtomicCompare和AtomicSwap是构建无锁数据结构的基石,而AtomicLoad/AtomicStore则常用于实现内存屏障和顺序一致性保证。
以AtomicLoad操作为例,其典型消息流如下:
请求阶段:
数据收集阶段:
执行阶段:
plaintext复制典型AtomicLoad消息序列:
RN-F0 → HN-F: AtomicLoad
HN-F → RN-F0: DBIDResp
HN-F → RN-F1/RN-F2: SnpUnique
RN-F2 → HN-F: SnpRespData_I_PD
HN-F → RN-F0: CompData_I
HN-F → SN-F: NCBWrData(NewData)
NCBWrData是原子事务中的核心消息类型,具有以下特点:
与CopyBackWriteData(CBWrData)相比,NCBWrData不要求数据来自缓存,而是直接由请求节点提供,这使得它在原子操作中更为高效。
独占访问是多核系统中实现临界区保护的另一种重要机制,其核心思想是通过"加载-修改-存储"的原子序列实现互斥。
典型的独占访问序列包含三个阶段:
独占加载(Exclusive Load):
数据计算:
独占存储(Exclusive Store):
ARM定义了两种监控器协同工作:
特性:
特性:
c复制// 典型独占访问代码示例
int atomic_increment(int *value) {
int old_value;
do {
old_value = __ldrex(value); // 独占加载
new_value = old_value + 1;
} while(__strex(new_value, value)); // 独占存储
return old_value;
}
内存类型对独占访问的实现有重大影响:
| 特性 | 侦听内存(Snoopable) | 非侦听内存(Non-snoopable) |
|---|---|---|
| 监控器类型 | LP+PoC双监控器 | 单一系统监控器 |
| 位置要求 | 必须位于PoC | 可位于PoS或终端设备 |
| 典型应用 | 多核共享内存 | 设备寄存器访问 |
| 实现复杂度 | 高(需维护一致性) | 相对简单 |
WriteBackFull是典型的回写事务,其消息序列如下:
关键点:
在某些场景下,原子操作可直接在SN-F执行,显著降低延迟:
优势:
当CopyBack请求与Snoop请求同时发生时:
当ReadShared和WriteBack同时到达HN-F:
地址监控器粒度选择:
局部性优化:
退避策略:
推测执行:
批处理优化:
缓存友好设计:
基于独占访问的自旋锁核心逻辑:
获取锁:
释放锁:
assembly复制; ARM汇编自旋锁示例
spin_lock:
ldrex r1, [r0] ; 独占加载锁状态
cmp r1, #0 ; 检查是否可用
wfene ; 等待事件(可优化功耗)
strexeq r1, r2, [r0] ; 尝试获取锁
cmpeq r1, #0 ; 检查是否成功
bne spin_lock ; 失败则重试
dmb ; 内存屏障
bx lr
利用AtomicCompare实现的多生产者队列:
入队操作:
出队操作:
基于AtomicLoad/AtomicStore的计数器实现:
递增操作:
读取操作:
在实际系统设计中,选择原子事务还是独占访问取决于具体场景。原子事务适合简单的读-修改-写操作,而独占访问更适合复杂的临界区保护。理解NCBWrData等协议消息的流动规律,以及PoC监控器的工作原理,对于设计高性能并发数据结构至关重要。