linux pthread_suspend

11

看起来Linux没有实现pthread_suspend和pthread_continue,但我确实需要它们。

我尝试过使用cond_wait,但速度太慢了。这些线程执行的工作大多在50微秒内完成,但有时会执行超过500毫秒的任务。cond_wait的问题有两个。第一,互斥锁需要占用与微秒级别执行时间相当的时间,而且我不需要锁定。第二,我有很多工作线程,不想为每个线程都创建一个条件变量。

我知道哪个线程正在等待哪项工作,可以直接pthread_continue那个线程。线程知道何时没有更多的工作并且可以轻松地pthread_suspend自己。这样不需要锁定,避免了锁竞争,速度也更快。问题是...没有pthread_suspend或者_pthread_continue。

有什么想法吗?


将更大的工作块分派给线程,以便锁定成本成为较小的%开销?(线程花费更多时间工作,而不是委派工作?) - Thanatos
工作有时候很大...除非你尝试过,否则无法确定。我已经以一种不需要锁定的方式分派了工作...但我还没有找到低成本挂起和唤醒线程的最佳方法...cond_wait为每个被唤醒的线程锁定互斥量。它也不允许您只唤醒一个线程。我可以为每个线程创建一个条件...啊...肯定有更好的方法。cond_wait似乎适用于用户GUI线程,但不适用于高速交易。 - johnnycrash
明天我会查看cond_wait的源代码,并对信号和管道方法与cond_wait进行性能测试。 - johnnycrash
如果你要进入内核空间,我认为没有任何东西能像你想要的那样快...而且如果不进入内核空间,你真的无法做任何事情来睡眠... - Spudd86
5个回答

8

+1 对于一个有希望的答案。我今晚会测试一下,如果有效的话,我会告诉你答案。谢谢! - johnnycrash
忘了提到,你必须使用 pthread_kill 来向特定线程发送信号,否则你无法预测哪个线程将会恢复。 - jweyrich
3
我们对这种方法进行了测试,结果发现相比使用pthread_cond_wait,我们能够更快地使线程睡眠和唤醒,速度提高了40倍。 - johnnycrash
6
请问,你能分享一下你的测试吗?这样其他人就可以受益了。 - jweyrich

3

让线程在管道读取上阻塞。然后通过管道分发数据。线程将因为需要处理的数据到达而被唤醒。如果数据非常大,只需通过管道发送指针。

如果特定数据需要发送到特定线程,则需要每个线程一个管道。如果任何线程都可以处理任何数据,则所有线程都可以阻塞在同一个管道上,并且它们将轮流唤醒。


0

在我看来,这样的解决方案(即使用“pthread_suspend”和“pthread_continue”)不可避免地存在竞争。

工作线程完成工作并决定暂停自己之间可能会有任意数量的时间流逝,而实际暂停发生的时间也是不确定的。如果主线程在此期间决定让该工作线程再次工作,“continue”将没有效果,工作线程将无论如何暂停自己。

(请注意,这不适用于允许排队“continue”的挂起方法,例如其他答案中提到的“sigwait()”和“read()”方法)。


请注意,信号在NPTL上是排队的(至少如此)。 - jweyrich
2
@jweyrich:是的,你可以使用信号来实现,因为sigwait()函数有效地执行原子解除阻塞-等待-阻塞操作。 - caf
当调度程序将工作添加到循环工作队列时,它会检查相应的循环挂起队列。与工作相同索引处的挂起线程将被唤醒。唤醒的线程清除其挂起标志。调度程序会定期扫描挂起队列,寻找没有唤醒的线程(竞争条件),并再次发出信号。在处理完该挂起扫描后,需要重复执行该操作(可能需要休眠1毫秒),直到所有线程都唤醒并完成。由于竞争条件很少发生,我估计每100个事务中只有1个需要在最后进行额外的扫描。 - johnnycrash
原子非阻塞-等待-阻塞是什么意思? - johnnycrash
@johnnycrash:sigwait() 要求您在线程的信号掩码中阻止等待的信号。然后它等待该信号发生(有效地取消阻塞),并在返回时重新阻塞该信号。 - caf

0

或许可以尝试使用pthread_cancel选项,但如果有任何需要释放的锁,请小心操作。请阅读手册以确定取消状态。


0
你为什么关心哪个线程执行任务?听起来像是你自己设计的一个死角,现在需要一个技巧来解决。如果让已经在运行的线程执行任务,你就不需要这个技巧了,而且上下文切换也会更少。

有一个线程池。还有一个线程列表,它们正在等待工作完成或处于空闲状态。如果新的工作项恰好是等待线程的依赖项,则唤醒该线程;否则,我会唤醒一个空闲线程。信号让我可以针对特定的睡眠线程或第一个空闲线程。我编写了自己的工作队列,使用原子操作而不是互斥锁和条件变量。这使得开销足够低,即使工作项需要微秒级别的时间,也能保持性能。我只需要偶尔像互斥锁或条件变量一样使线程休眠即可。 - johnnycrash
@johnnycrash 这听起来像是糟糕的设计。为什么要有一个特定的线程等待一个特定的事情呢?你可以在不需要线程等待的情况下等待X发生,然后安排任何线程执行Y。当X发生时,你就可以让任何线程执行Y。你的设计会强制你解决唤醒特定线程的问题,然后强制进行额外的上下文切换和调度器/缓存惩罚,因为那个线程可能在此时执行效率低下。 - David Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接