【问题标题】:sleeping on an event在活动中睡觉
【发布时间】:2012-07-31 21:03:56
【问题描述】:

我有一个多线程程序,我在一个线程(线程 A)中无条件地休眠无限时间。当另一个线程(线程 B)中发生事件时,它通过信号唤醒线程 A。现在我知道有多种方法可以做到这一点。 当我的程序在 Windows 环境中运行时,我在 Thread-A 中使用 WaitForSingleObject,在 Thread-B 中使用 SetEvent。它工作没有任何问题。 我还可以使用基于文件描述符的模型进行轮询、选择。有不止一种方法可以做到这一点。 但是,我正在尝试找到最有效的方法。每当 Thread-B 发出信号时,我想尽快唤醒 Thread-A。你认为什么是最好的选择。 我可以探索基于驱动程序的选项。

谢谢

【问题讨论】:

  • 用事件或信号量发出信号是否不够有效?线程 A 通常应该立即准备好,并从其先前等待信号的状态提升优先级。如果没有可用的核心,如果它们的基本优先级相同,它可能会抢占信号器。你有实际问题吗?我看不出司机会如何帮助任何人。
  • 我可能没有问题。但我的理解是,每种机制的工作方式都大不相同。例如。如果我使用一个事件,那么我请求内核安排一个事件。如果我使用 poll-select 然后我写入一个系统理解的文件,然后唤醒我的睡眠线程。因此,两者都有不同的延迟。从线程-B,我可以从线程-A 执行 IOCTL,然后向线程-A 发出信号。所以,我想知道是否有任何特定的方法比其他方法快得多。
  • 您为什么不尝试对各种方法进行基准测试?由于您的性能计数器对所有线程和进程都是通用的,因此创建一个内存区域,线程 B 可以在其中标记其信号时间,线程 A 可以标记其唤醒时间(使用 QueryPerformanceCounter)。对数千次重复执行此操作并平均延迟。这可能很疯狂,但您也可以尝试在线程 A 中等待一个 volatile 标志,然后让线程 B 设置该标志并立即让自己进入睡眠状态。
  • 我在同一个问题上研究了一段时间。结果:事件!基准测试将显示从设置事件到等待功能唤醒的时间不到 2 微秒。但是:优先级设置、处理器亲和性和整个系统负载都会影响结果。
  • @Arno - 是的。如果两个线程都绑定到同一个内核,操作系统不必执行任何内核间通信来使线程 A 在另一个内核上运行 - 它可以直接抢占线程 B。当然,这确实意味着 B 被留下不执行 - 如果不调整亲和力,则可以避免这种情况,因此可能会损害整体性能:(

标签: c windows multithreading


【解决方案1】:

如前所述,在线程 B 中触发 SetEvent 并在线程 A 中触发 WaitForSingleObject 很快。 但是必须考虑一些条件:

  • 单核/处理器:正如 Martin 所说,等待线程将抢占信号线程。使用这样的方案,您应该注意信号线程 (B) 在SetEvent 之后立即空闲。例如,这可以通过sleep(0) 来完成。

  • 多核/处理器:人们可能认为将两个线程放在不同的核/处理器上会有好处,但这并不是一个好主意。如果两个线程在同一个内核/处理器上,则调用 SetEvent 和返回 WaitForSingleObject 之间的时间跨度要短得多。

  • 在一个内核上处理两个线程 (SetThreadAffinityMask) 还允许通过它们的优先级设置 (SetThreadPriority) 来处理它们的行为。您可以以更高的优先级运行等待线程,或者您必须确保信号线程在设置事件后确实没有做任何事情。

  • 您必须处理其他一些同步问题:下一个事件何时发生?线程 A 会完成它的任务吗?最有效的第二个事件可以用来解决这个问题:当线程 A 完成时,它设置一个事件以指示允许线程 B 再次设置它的事件。线程 B 会有效地先设置事件,然后等待反馈事件,满足立即进入空闲状态。

  • 如果您希望允许线程 B 设置事件,即使线程 A 尚未完成且尚未处于等待状态,您应该考虑使用信号量而不是事件。这样,来自线程 B 的“调用/事件”的数量得以保持,线程 A 中的等待函数可以跟进,因为它返回的信号量已被释放的次数。信号量对象的速度与事件差不多。

总结:

  • 通过SetThreadAffinityMask 让两个线程在同一个核心/cpu 上。

  • 通过另一个事件扩展SetEvent/WaitForSingleObject以建立Handshake

  • 根据处理的细节,您也可以考虑semaphore objects

【讨论】:

  • 非常感谢!!!我的线程是两个不同的硬件线程,我希望它们以这种方式运行。所以,我需要弄清楚如何有效地跨核心使用信号。
  • 我怀疑你会比已经存在的操作系统内核间通信驱动程序做得更好。它通过向目标内核发出硬件中断以强制其进入操作系统并因此“拾取”线程“A”来使“A”运行。可能有一些令人毛骨悚然的轮询方法可以仅改善此操作的延迟,但会损害其他一切:(
  • @agent.smith:我猜你说的不是不同的处理器,而是同一个处理器的不同内核。我的测量结果表明,开销更大。我确实在SetEvent()WaitForSingleObject() 之间捕获了大约 3.5 微秒的时间来返回。 Semaphore 方法花了大约 5 微秒。我发现这种额外的开销取决于硬件,而在同一个内核上执行此操作时我看不到太多的硬件依赖性。但是,多核的目的是将工作分配给它们。
  • @Arno:非常感谢!!!我在不同的内核上运行线程。我认为我需要坚持使用 SetEvent() 和 WaitForSingleObject()。我还将尝试使用基于文件描述符的 poll-select 并让您知道延迟。我不认为 SetEvent 会更快。
猜你喜欢
  • 2011-10-19
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多