我试图找出Pi Pico中使用的ARM Cortex-M0是否支持像
fetch_and_add
或compare_and_swap
这样的原子指令,我发现了一个线程解释说Cortex-M0没有这样的指令。相反,为了实现原子性,必须依赖特殊的自旋锁外设和 C/C++ SDK 提供的支持。
在检查SDK中
sync.h
中的具体自旋锁实现时,遇到了几个问题:
spin_lock_blocking
的实现:这里,首先禁用中断,然后调用spin_lock_unsafe_blocking
,它在锁变量上自旋,然后断言内存栅栏。
问题:
禁用中断肯定会停止同一核心上的抢占,但是如何确保两个核心不会尝试同时读取/修改/写入锁定变量呢?他们在评论中说等待另一个核心,但是如何呢?在其他一些处理器上,这项工作将由 while 循环内的
test_set
指令完成,但这里它仅读取指针值。这样安全吗?
一旦获得锁,内存屏障的目的是什么?
我不清楚
spin_lock_unsafe_blocking
实现中的评论。 “永不阻塞”是什么意思?
以下代码来自sync.h
#define __builtin_expect(x, y) (x)
__force_inline static void spin_lock_unsafe_blocking(spin_lock_t *lock) {
// Note: we don't do a WFE or anything because, by convention, these spin locks are VERY SHORTLIVED and **NEVER BLOCK** and run
// with INTERRUPTS disabled (to ensure that)... therefore, nothing on our core could be blocking us, so we just **need to wait** on another core
// anyway, which should be finished soon
while (__builtin_expect(!*lock, 0));
__mem_fence_acquire();
}
__force_inline static uint32_t spin_lock_blocking(spin_lock_t *lock) {
uint32_t save = save_and_disable_interrupts();
spin_lock_unsafe_blocking(lock);
return save;
}
- 禁用中断肯定会停止同一核心上的抢占,但如何确保两个核心都不会尝试抢占 同时读取/修改/写入锁定变量?
硬件,大概是为了“同时”的相关定义。为了实现远程正确,系统的内存控制器必须提供对
spin_lock_t
类型(可能是整数)对象的读取和写入以原子方式执行(即使在 memory_order_relaxed
意义上也足够了)。对于任何特定硬件来说,这是一个有效的假设并不特别令人惊讶,尽管做出这样的假设一般来说并不安全。
他们在评论中 说等待另一个核心,但是怎么办?
while
循环循环,直到
*lock
非零。该实现似乎期望如果
*lock
最初为 0,那么在另一个核心上运行的某些东西很快就会将其设置为非零。这就是“自旋锁”中的“自旋”。然而,所提供的两个函数实际上都没有像我期望的那样修改
*lock
的值,以实现bona fide 锁。如果没有原子 CAS(又名测试/设置)或类似的东西,你就无法真正正确地做到这一点,但你展示的实现甚至没有尝试。我认为它实际上并没有提供任何锁定。
__builtin_expect()
宏大概是作为一个可以插入原子CAS的配置点。
在其他一些处理器上,这 工作将由 while 循环内的 test_set 指令完成,但是 这里只是读取指针值。这样安全吗?据我所知,这个函数不提供
真正的锁定行为。所以不行。即使在单核机器上也不行。
锁定具有内存排序和可见性语义。粗略地说,一旦获得锁,内存屏障的目的是什么?
这是“块”一词的奇怪用法。我认为这应该意味着在该函数中运行的线程永远不会被我不清楚 spin_lock_unsafe_blocking 实现中的注释。他们所说的“从不”是什么意思 阻止'?
抢占。