我一直在对基于 futex 的锁使用等待者计数方法:与 futex 相邻int
,有一秒钟int
是等待者计数,等待者在执行 futex 等待操作之前竞争锁原子地增加,并在从返回时原子地减少futex 系统调用。但是,我注意到,当运行的线程数大于 cpu 数时,就执行的无用唤醒系统调用的数量而言,这具有病态的不良属性,如下所示:
线程 A 在 futex 上挂起等待,因此等待者计数增加,但它不会很快再次收到时间片,因为所有 cpu 都在使用中。同时,线程 B 正在快速执行临时获取和释放锁的操作。每次,它都会看到有一个等待者,因此会进行 futex 唤醒系统调用,尽管线程 A 已经被发送了一个唤醒并且还没有机会运行并从等待者计数中减少自己。
有什么好办法解决这个问题吗?我觉得应该有一些安全的方法让发送唤醒事件的线程执行相当于减少服务员计数的操作(直接这样做似乎是不可能的,因为很难协商,因此不会发生多次递减)。int
如有必要,可以接受向锁定状态添加一个或多个额外字段。
我知道的另一种设计是在服务员计数之前,而在原子锁定int
本身上只有一个争用标志。这样做的方式是,解锁操作清除标志,并在发现锁定后尝试(成功与否)获取锁定设置标志。解锁时,如果设置了标志,则执行唤醒操作。我相信这种设计避免了我遇到的问题,但它有一个不同的问题:在低竞争下,在持有锁时到达的服务员将在释放锁时无条件地进行 futex 唤醒系统调用,即使没有其他服务员。也许这种设计可以与服务员数量混合,以消除部分或全部虚假唤醒系统调用?