如果我有 EventWaitHandle,我需要锁吗

Do I need a lock if I have EventWaitHandle

albahari atricle开始研究多线程。 我需要在下面的示例中使用锁 _locker 吗?我想不会,因为 _message 受到 EventWaitHandle 的保护。我说得对吗?

class TwoWaySignaling
{
  static EventWaitHandle _ready = new AutoResetEvent (false);
  static EventWaitHandle _go = new AutoResetEvent (false);
  static readonly object _locker = new object();
  static string _message;

  static void Main()
  {
    new Thread (Work).Start();

    _ready.WaitOne();                  // First wait until worker is ready
    lock (_locker) _message = "ooo";
    _go.Set();                         // Tell worker to go

    _ready.WaitOne();
    lock (_locker) _message = "ahhh";  // Give the worker another message
    _go.Set();
    _ready.WaitOne();
    lock (_locker) _message = null;    // Signal the worker to exit
    _go.Set();
  }

  static void Work()
  {
    while (true)
    {
      _ready.Set();                          // Indicate that we're ready
      _go.WaitOne();                         // Wait to be kicked off...
      lock (_locker)
      {
        if (_message == null) return;        // Gracefully exit
        Console.WriteLine (_message);
      }
    }
  }
}

你是对的。

这类问题不能简单地通过反复试验来测试。最好用逻辑思维来分析它们:

  • 哪个线程运行哪个代码?
  • 另一个线程现在会发生什么?
  • 如果另一个线程获得更多 CPU 时间会怎样?等等

主线程只会执行Main()中的代码,工作线程只会执行Work()中的代码。所以这很简单。

如果您查看关键资源的访问方式,您会注意到 Main() 中对 _message 的访问始终介于

之间
_ready.WaitOne();

_go.Set();

而在 Work() 中访问 _message 总是在

之间
_go.WaitOne();

_ready.Set();

因此,其中一个线程在访问 _message 之前将始终等待另一个线程,因此不需要锁。

您阻止线程同时访问 _message 变量。您的逻辑在这里是自给自足且可预测的,但情况并非总是如此。有时你会从其他地方读取并且流程不是完全可控的,在这种情况下你需要锁定关键变量。