我一直在使用基于futex的锁的服务器计数方法:与futex int
相邻,有第二个int
,这是服务员计数,服务员争用锁原子增量之前执行futex等待操作,并在从futex系统调用返回时原子递减。但是,我注意到,当运行的线程数大于cpus的数量时,就无效唤醒系统调用的数量而言,这具有病态上的不良属性,如下所示:
线程A暂停等待futex,因此服务器计数递增,但它不会很快再次收到时间片,因为所有cpu都在使用中。同时,线程B正在快速执行暂时获取和释放锁定的操作。每次,它都会看到有一个服务员,因此进行了一个futex唤醒系统调用,尽管事实上线程A已经被唤醒并且还没有机会从服务员计数中运行和减少。< / p>
这有什么好办法吗?我觉得应该有一些安全的方法让线程发送唤醒事件来做相当于减少服务员数量(直接这样做似乎不可能,因为它很难协商,因此多次减少不会发生)。如有必要,可以接受将一个或多个额外int
字段添加到锁定状态。
我知道的一个替代设计是在服务员计数之前,而在原子锁int
本身上只有一个争用标志。这样做,解锁操作清除标志,并在发现被设置标志后尝试(成功与否)获取锁定。在解锁时,如果设置了标志,则执行唤醒操作。我相信这个设计可以避免我遇到的问题,但它有一个不同的问题:在低争用下,在锁定时到达的服务员将无条件地在释放锁时进行futex唤醒系统调用,即使没有其他服务员。也许这个设计可以与服务员计数混合,以消除一些或所有虚假的唤醒系统调用?
答案 0 :(得分:0)
我相信发送唤醒事件的线程可以执行减量,并且仍然保持准确的服务员计数。关键细节是:
FUTEX_WAIT返回是否被FUTEX_WAKE(零)或其他(非零)唤醒的指示。被FUTEX_WAKE唤醒的服务员不应该减少服务员的数量(它应该假设waker代表它这样做);因任何其他原因而被吵醒的服务员应减少计数(除非当然会立即再次等待)。
FUTEX_WAKE返回被唤醒的线程数:waker应该将服务员数减少这个数字。
重要的是,双方都知道减少服务员数量的责任是否已成功移交。
当然,魔鬼总是在细节之中,这个方案是否是严格管理服务员的最有效方式将取决于它与其他锁定方案的整合程度 - 但它当然值得考虑。