首页 > 解决方案 > 我可以在此 ManualResetEvent 中使用锁来确保线程安全吗?

问题描述

假设我有两个操作计数的函数和一个定期触发的 OnTimer 函数。

void IncrementCount()
{
    _myCount++;
}

void OverwriteCount(int newValue)
{
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
}

我的愿望是,如果/当调用 OverwriteCount 时,在计时器函数执行之前不能执行 IncrementCount。

我最初的想法是使用 ManualResetEvent 来帮助同步行为:

private static ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);

void IncrementCount()
{
    mre.Wait(-1); // can't increment until the event is signaled
    _myCount++;
}

void OverwriteCount(int newValue)
{
    mre.Reset(); // unsignal the event, blocking threads
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
    mre.Set(); // signal the event
}

我担心的是一个退化的多线程场景,其中线程 A 超过了 IncrementCount() 中的 mre.Wait() 但实际上还没有增加 _myCount。线程 B 然后调用 mre.Reset() 并覆盖 _myCount。然后线程 A 转一圈并增加 _myCount。

我可以通过在 IncrementCount() 和 OverwriteCount() 中添加一个锁来解决这个问题,以确保一次只有一个线程可以修改 _myCount 吗?如果在持有锁的同时等待重置事件,我是否会面临死锁的风险?

标签: c#.netconcurrency

解决方案


如果我理解您,那么是的,如果您选择适当锁定的内容,它将起作用。可能有一种更精细的方法可以做到这一点,但到目前为止我认为这没有任何问题

void IncrementCount()
{
   mre.Wait();

   // lets not cause a race, lock until OverwriteCount is finished
   lock (_sync)
   {
      _myCount++;
   }
}

void OverwriteCount(int newValue)
{
   // lock this so we can assure the count is updated
   lock (_sync)
   {
      mre.Reset(); // unsignal the event, blocking threads
      _myCount = newValue;
   }
}

void OnTimer()
{
   Console.WriteLine(_myCount);
   mre.Set(); // signal the event
}

推荐阅读