1

我一直在对基于 futex 的锁使用等待者计数方法:与 futex 相邻int,有一秒钟int是等待者计数,等待者在执行 futex 等待操作之前竞争锁原子地增加,并在从返回时原子地减少futex 系统调用。但是,我注意到,当运行的线程数大于 cpu 数时,就执行的无用唤醒系统调用的数量而言,这具有病态的不良属性,如下所示:

线程 A 在 futex 上挂起等待,因此等待者计数增加,但它不会很快再次收到时间片,因为所有 cpu 都在使用中。同时,线程 B 正在快速执行临时获取和释放锁的操作。每次,它都会看到有一个等待者,因此会进行 futex 唤醒系统调用,尽管线程 A 已经被发送了一个唤醒并且还没有机会运行并从等待者计数中减少自己。

有什么好办法解决这个问题吗?我觉得应该有一些安全的方法让发送唤醒事件的线程执行相当于减少服务员计数的操作(直接这样做似乎是不可能的,因为很难协商,因此不会发生多次递减)。int如有必要,可以接受向锁定状态添加一个或多个额外字段。

我知道的另一种设计是在服务员计数之前,而在原子锁定int本身上只有一个争用标志。这样做的方式是,解锁操作清除标志,并在发现锁定后尝试(成功与否)获取锁定设置标志。解锁时,如果设置了标志,则执行唤醒操作。我相信这种设计避免了我遇到的问题,但它有一个不同的问题:在低竞争下,在持有锁时到达的服务员将在释放锁时无条件地进行 futex 唤醒系统调用,即使没有其他服务员。也许这种设计可以与服务员数量混合,以消除部分或全部虚假唤醒系统调用?

4

1 回答 1

0

我相信有可能让发送唤醒事件的线程执行递减,并且仍然保持准确的服务员计数。关键细节是:

  • FUTEX_WAIT 返回是否被 FUTEX_WAKE(零)或其他东西(非零)唤醒的指示。由 FUTEX_WAKE 唤醒的服务员不应该减少服务员计数(它应该假设唤醒器代表它这样做);由于任何其他原因被唤醒的服务员应该减少计数(当然,除非它会立即再次等待)。

  • FUTEX_WAKE 返回被唤醒的线程数:唤醒者应该将等待者计数减少这个数字。

重要的一点是双方都知道递减服务员人数的责任是否已经成功移交。

当然,魔鬼总是在细节中,这个方案是否严格来说是管理服务员的最有效方式将取决于它与其他锁定方案的集成程度 - 但它当然值得考虑。

于 2014-09-18T12:49:29.683 回答