在ManualResetEvent或Thread.Sleep()之间做出选择

我不确定采用哪种策略……我专注于我的操作完成,但我也想将性能问题保持在最低限度……有一种名为Execute()的方法必须等待(同步运行)直到操作完成。 此操作发生在另一个线程上。 有两种方法可以实现同样的事情……

通过使用ManualResetEvent

void Execute() { taskHandle = new ManualResetEvent(false); . . //delegate task to another thread . . taskHandle.WaitOne(); } 

要么

通过使用简单的while构造

 void Execute() { . . //delegate task to another thread . . while (!JobCompleted) Thread.Sleep(1000); } 

我应采用两种方法中的哪一种……为什么?

编辑:

Q2。 如果我在构造时只是空了怎么办? 有什么不同…?

 while(!JobCompleted); 

编辑:(之前我收集过的东西)

http://www.yoda.arachsys.com/csharp/threads/waithandles.shtml – 这篇文章说手动复制比较慢,因为它们离开了托管代码并重新进入……

出于好奇,为什么ManualResetEvent而不是AutoResetEvent ? 无论哪种方式,通过睡眠 – 检查 – 睡眠方法与OS原语一起使用。

您也可以使用Monitor锁(通过Monitor.EnterMonitor.Exit显式,或通过lock块),但方法应该基于您实际执行的操作; 如果它是“只有这些东西之一 ,我需要独占访问”的场景,那么使用Monitor锁。 如果它是“我需要等到另一个线程因资源访问以外的原因而完成 ”,那么使用AutoResetEventManualResetEvent

使用Thread.Join的建议是好的(如果)

  1. 您可以访问其他Thread对象
  2. 另一个线程终止之前,您不希望执行。

如果其中任何一个不是真的(你没有访问权限,或者其他线程不会终止,它只会发出“全部清除”的信号),那么Thread.Join就不可行了。

最糟糕的选择是

while(!JobCompleted);

因为这会将处理器与变量的不必要检查联系起来而不会在它们之间产生任何停顿。 是的,它将阻止你的线程,直到操作完成,但你将最大化CPU使用率(或至少一个核心的价值)。

该事件可以更有效地使用处理器 – 您不必将父线程唤醒以进行轮询。 当事件触发时,内核会唤醒你。

如果您可以访问原始的Thread对象,或者可以获得该访问权限,那么最好使用Thread.Join()

编辑:另外,如果这是在WinForms或WPF等GUI中进行的,您可能需要考虑使用BackgroundWorker

使用Thread.Sleep()的主要缺点是你决定线程将等待多长时间。 您正在等待的操作可能需要更多更少的时间,并且通常,很难精确地量化该时间。 如果线程睡眠时间过长,那么您没有充分利用系统资源。

为了达到最佳效果,您应该使用ManualResetEvent (或AutoResetEvent ),以便在依赖操作完成后立即恢复您的线程。

ManualResetEvent绝对是最佳选择。

从您提供的代码段中,您似乎在Execute方法中委派执行。 如果是这种情况,并且您只委派一个任务,那么如果您必须等待响应,为什么还要委托给另一个线程呢? 您也可以同步执行该过程。

手动复制比较慢,因为它们离开托管代码并重新进入..

它们可能比说Wait / Pulse组合,我认为你应该在这里使用它 。 但是,即使您选择x = 1Manual/AutoResetEvents也会比您执行的任何Thread.Sleep(x)更快。 即使您将Windows计时器分辨率降低到1毫秒。

如果我在构造时只是空了怎么办? 有什么不同…?

然后一个核心将以100%旋转直到条件变为真,从其他线程中偷走时间,而不是使用它来做一些有用的事情,比如计算“愤怒的小鸟”的帧 – 或者cpu可以简单地冷却一下,延迟全球变暖的可怕影响将持续一些纳秒。

两种方法基本上都做同样的事情。 然而,while循环更明确一些,因为您可以指定睡眠时间。 虽然我会使用在你工作的场景中使用的XXXResetEvent类。我会假设线程类现在或稍后实现,具有更强大的线程代码来处理多核处理器上的线程关联。