【问题标题】:AutoResetEvent accumulative Sets()AutoResetEvent 累积 Sets()
【发布时间】:2018-07-31 13:36:22
【问题描述】:

我编写了这段代码作为概念验证,以检查我在当前项目中试验的问题。

var sleeper = new AutoResetEvent(false);

        sleeper.Set();
        sleeper.Set();
        sleeper.Set();

        var ix = 0;
        while(true) {
            sleeper.WaitOne();
            Console.Write(ix++);
        }

令人惊讶的是(至少对我而言)我没有得到预期的结果。 我希望在控制台中打印012,但只打印0

  • 我误会了什么?
  • 哪种方法可能是解决此问题并获得预期结果的最佳方法?

【问题讨论】:

  • AutoResetEvent 已经处于信号状态时,调用Set() 不会执行任何操作。你可能想看看使用 SemaphoreSemaphoreSlim 来保持这样的计数。

标签: c# .net multithreading synchronization


【解决方案1】:
  1. 您的代码的实际输出是0

  2. AutoResetEvent 没有内存,它要么有信号,要么没有。在它发出信号后,您正在等待它。你的情况的事件顺序:

    • 创建 AutoResetEvent(状态 = 0)
    • 信号 AutoResetEvent(状态 = 1)
    • 信号 AutoResetEvent(状态 = 1)
    • 信号 AutoResetEvent(状态 = 1)
    • 开始等待事件(处理当前信号状态 1 并将其切换为 0)
    • 继续等待事件

如 msdn AutoResetEvent description 中所述

另外,如果 Set 在没有线程等待并且 AutoResetEvent 已发出信号,调用无效。

  1. 要观察所需的行为,您需要第二个线程(因为 AutoResetEvent 是为线程间通信而创建的)。

这样的东西应该适合你

private static AutoResetEvent sleeper;

static void Main()
{
    sleeper = new AutoResetEvent(false);

    Thread t = new Thread(ThreadProc);
    t.Start();

    var ix = 0;
    while(true) 
    {
        sleeper.WaitOne();
        Console.Write(ix++);
    }
}

static void ThreadProc()
{
    Thread.Sleep(1000);
    sleeper.Set();
    Thread.Sleep(1000);
    sleeper.Set();
    Thread.Sleep(1000);
    sleeper.Set();
}
  1. 请注意,AutoResetEvent保证它将处理以下代码的 3 个事件

    sleeper.Set();
    sleeper.Set();
    sleeper.Set();
    

如其'description 中所述 因此Thread.Sleep(1000) 位。

不能保证每次调用 Set 方法都会释放一个 线。如果两个电话靠得太近,那么第二个电话 发生在线程被释放之前,只有一个线程被释放。 就好像第二次通话没有发生一样。

【讨论】:

  • 完全正确!输出为0!我要修复它;)
猜你喜欢
  • 2018-05-13
  • 1970-01-01
  • 2019-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 2013-11-08
  • 2019-05-04
相关资源
最近更新 更多