【问题标题】:ManualResetEvent vs while loopManualResetEvent 与 while 循环
【发布时间】:2013-12-09 06:50:23
【问题描述】:

ManualResetEvent 基本上对其他线程说“只有在收到继续的信号时才能继续”,并用于暂停某些线程的执行,直到满足某些条件。我想问的是,当我们可以通过使用while循环轻松实现我们想要的东西时,为什么ManualResetEvent?考虑以下上下文:

public class BackgroundService {

ManualResetEvent mre;
public BackgroundService() {
    mre = new ManualResetEvent(false);
}
public void Initialize() {
    // Initialization
    mre.Set();
}

public void Start() {
    mre.WaitOne();
    // The rest of execution
}
}

有点类似

public class BackgroundService {

bool hasInitialized;
public BackgroundService() {

}
public void Initialize() {
    // Initialization
    hasInitialized = true;
}

public void Start() {
    while (!hasInitialized)
    Thread.Sleep(100);
    // The rest of execution
}
}

ManualResetEvent 是否比 while 循环更合适?

【问题讨论】:

  • ManualResetEvent 更准确。在最坏的情况下,您的循环可能会浪费 99 毫秒。
  • 线程在 while 循环中是相同的,因为它实际上无法执行任何其他工作,就像您有多个线程一样,可能存在某些区域可能需要一些指示继续做下一个线程做的事情,例如,可能是批处理结果,其中 T1 对它们进行批处理,引发一个信号,然后 T2 可能正在执行批处理的批处理插入/处理。这只是一个例子——每个线程都致力于做某事。单个线程不会那么多,性能和可维护性可能会很慢
  • 如何使用while循环实现线程同步?使用手动重置事件很简单直接。您还需要从我认为的设计角度考虑哪种结构适合您的需求。

标签: c# manualresetevent


【解决方案1】:

ManualResetEvent 是否比 while 循环更合适?

当然。有两个主要原因:延迟和效率。

上下文切换线程以重新开始运行是相对昂贵的,当它刚刚回到睡眠状态时,您给出的方法将平均需要 50 毫秒来响应正在设置的 hasInitialized 变量- 假设它完全响应。 (您没有任何显式内存屏障,因此线程可能根本看不到变量的更改。我怀疑调用Thread.Sleep 有效地添加了内存屏障,但不能保证。) OS/CLR 级别的同步原语,线程可以更快地响应。

【讨论】:

    【解决方案2】:

    使用ManualResetEvent 提供的信号更有效。使用 while 循环意味着大约每 100 毫秒后,即每秒 10 次,其他线程必须停止运行,因此检查条件的线程必须运行,当条件大多为假时,此上下文切换更少高效。

    但是在你的代码中有些东西闻起来很可疑,为什么在初始化某些东西时会有这样的代码轮询?如果初始化是异步的,那么已经有一些通知机制,例如回调,当它完成后轮询是不必要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-05
      • 2014-03-23
      • 2015-02-08
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多