C 用futex锁管理跟踪服务员最有效的方法是什么?

C 用futex锁管理跟踪服务员最有效的方法是什么?,c,linux,multithreading,futex,C,Linux,Multithreading,Futex,我一直在对基于futex的锁使用服务员计数方法:在futexint附近,有第二个int是服务员计数,服务员在执行futex等待操作之前自动递增锁,从futex系统调用返回后自动递减。但是,我注意到,当运行的线程数大于CPU数时,就执行的无用唤醒系统调用数而言,这在病理学上具有不好的属性,如下所示: 线程A被挂起等待futex,因此服务员计数增加,但它不会很快再次收到时间片,因为所有CPU都在使用中。同时,线程B正在快速执行操作,以瞬时获取并释放锁。每次,它都会看到有一个服务员,因此会进行fute

我一直在对基于futex的锁使用服务员计数方法:在futex
int
附近,有第二个
int
是服务员计数,服务员在执行futex等待操作之前自动递增锁,从futex系统调用返回后自动递减。但是,我注意到,当运行的线程数大于CPU数时,就执行的无用唤醒系统调用数而言,这在病理学上具有不好的属性,如下所示:

线程A被挂起等待futex,因此服务员计数增加,但它不会很快再次收到时间片,因为所有CPU都在使用中。同时,线程B正在快速执行操作,以瞬时获取并释放锁。每次,它都会看到有一个服务员,因此会进行futex wake系统调用,尽管线程a已经被发送了一个wake,只是还没有机会运行并从服务员计数中减去自己

有什么好办法吗?我觉得发送唤醒事件的线程应该有一种安全的方法来减少服务员数量(直接这样做似乎是不可能的,因为很难协商以避免多次减少)。如有必要,可以向锁定状态添加一个或多个额外的
int
字段


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

我相信发送唤醒事件的线程可以执行递减,并且仍然保持准确的服务员计数。主要详情如下:

  • FUTEX_WAIT返回是否被FUTEX_WAKE(零)或其他东西(非零)唤醒的指示。被FUTEX_WAKE唤醒的服务员不应减少服务员数量(应假定唤醒者代表其进行);因任何其他原因被叫醒的侍者应减少计数(当然,除非它立即再次等待)

  • FUTEX_WAKE返回唤醒的线程数:唤醒器应按此数字减少服务员计数

重要的一点是,双方都知道减少服务员数量的责任是否已成功移交


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

futex是一个打字错误吗<代码>互斥锁也许?@FiddlingBits:不,它是
futex
。请参阅和。愚蠢的问题:当线程到达锁时,服务员计数较高时,您是否尝试添加
yield()
?也就是说,
if(uuu原子u获取u添加(&waterr u计数,1)>SOME u常量)sched_yield()
希望锁固定器线程能够更快地获得时间片?我记得读过一些关于LKML上的“定向”
yield()
的讨论——这将允许当前线程直接向锁持有者/唤醒线程屈服——但我认为它在调度优先级方面造成的混乱会阻止它。。我看看能不能找到,找到了。这是2014年3月linux内核邮件列表上的线程“用户空间的抢占控制”。这两个线程可以被读取,例如和。@NominalAnimal:futex wait系统调用阻塞,因此对于新到达的服务员来说,显式地让步充其量是无用的,并且可能适得其反,除非我误解了你的意思。另一方面,如果有等待者希望给他们中的一个获得锁的机会,那么让线程释放锁可能是有理由的。问题是,在这个方案中,您会受到虚假唤醒的影响,这会导致服务员认为它是故意被唤醒的,而实际上它是被另一个线程唤醒的,该线程在进行原子更改以解锁一个对象(该对象随后被释放)并将其内存重新分配给正在看到虚假唤醒的新对象后,盲目地发送了一个
FUTEX_WAKE
。我能看到的唯一办法是签订一份全球合同,规定Futex的使用方式永远不会导致这种情况,但如果各种应用程序和库模块都在使用Futex,这是不可能强制执行的。还要注意的是,避免问题的唯一方法,即使你小心地努力避免,当有服务员时,不要使用原子,然后使用
FUTEX_WAKE
,而是使用
FUTEX_WAKE_OP
来进行唤醒(有效)关于原子内存操作的原子性。好吧-从最初的问题(你对整个环境有多大的控制权)到我的头脑,我还不清楚:)以原子方式解锁一个结构,然后调用
FUTEX\u WAKE
,这是一个bug,因为通过解锁结构,您已经放弃了以任何方式访问它的权利(在您调用
FUTEX_WAKE
时,内存甚至可能未映射);通常,解决方案是将对对象本身的访问(对象的锁)的保护与对对象的保护分开