assembly 在使用mwaitx时,如何解决阿坝问题?

pxiryf3j  于 2023-01-13  发布在  其他
关注(0)|答案(1)|浏览(170)

AMD的mwaitx指令允许你等待一个地址改变,但它有一个有限的持续时间,没有办法告诉它是因为值改变还是因为中断而醒来。
您可以随时检查地址是否被更改,但这会导致阿坝问题,即地址可能已经更改,然后又更改回来。
这可能会导致这样一个问题:如果数据块的关联锁被访问,您可能希望发送数据块的更新请求,但如果获取、使用然后释放锁,则数据结构发生了更改,但锁的值似乎没有发生更改,并且使用mwaitx的线程不知道锁被访问。
有什么解决办法吗?还是我被卡住了?

nwwlzxa7

nwwlzxa71#

我们的想法是将mwaitx作为一种优化,而不是作为唯一的同步原语,对于这个用例,即使偶尔失败也没关系。
例如,假设您要Assert自旋锁

mutex   dd 0

如果它之前持有0,则将其设置为1。简单的方法是忙着等待锁变为零,例如:

again:  mov     ebx, 1
        xchg    [mutex], ebx  ; try to claim mutex
        test    ebx, ebx      ; did we succeed?
        jnz     again         ; if not, try again

这个循环当然效率很低:如果锁被另一个线程持有,它会旋转得非常快,导致大量代价高昂的RMW总线访问。我们可以使用pause指令来降低负载,但更好的是,一旦我们知道锁被持有,我们只会在知道另一个线程已经释放锁时尝试声明它。
monitor/mwait指令提供了一种实现此操作的工具:你设置了一个被监控的地址,然后当有趣的事情发生时,你会被注意到。只有在那时,你才试图声明锁,如果你知道你不会得到它,你就不会被浪费。如果mwait提前返回,也没有什么坏处:你就不能拿到锁然后又回去等它。

again:  mov     ebx, 1
        xchg    [mutex], ebx  ; try to claim mutex
        test    ebx, ebx      ; did we succeed?
        jz      gotit

        lea     rax, [mutex]  ; address to monitor
        xor     ecx, ecx      ; no extensions
        xor     edx, edx      ; no hints
        monitor               ; start to monitor the mutex
        xor     ecx, ecx      ; no extensions
        xor     eax, eax      ; no hints
        mwait                 ; wait for mutex to change
        jmp     again         ; once it changed, try to get the lock again

gotit:  ...

虽然这一切都很好,但还有一个新问题:如果另一个线程暂时不让步,复杂的互斥体实现可能希望切换到另一个实现,例如,内核负责锁的实现。这允许等待锁变得可用,而线程不必实际运行,从而为其他用户释放资源。
使用monitormwait很难实现这一点:等待时间是不确定的,可能会很长。AMD的mwaitxmonitorx指令非常相似,但修复了此问题:它们允许您设置一个超时,在此之后,即使内存区域没有更改,mwaitx也会返回。这样,您可以使用类似“尝试通过旋转和等待来声明锁10次,然后升级到基于内核的锁”的算法,并合理地确定执行所需的时间帧。

相关问题