c# - AutoResetEvent - 两次快速调用不能保证线程释放 - 为什么?

标签 c# warnings msdn autoresetevent

我正在阅读 MSDN 上的 AutoResetEvent 文档,随后的警告有点让我困扰......

“重要: 不能保证每次调用 Set 方法都会释放一个线程。如果两次调用距离太近,以至于第二次调用发生在一个线程被释放之前,则只释放一个线程。就好像第二个电话没有发生一样。此外,如果在没有线程等待且 AutoResetEvent 已发出信号时调用 Set,则调用无效。”

但是这个警告基本上扼杀了拥有这种线程同步技术的真正原因。例如,我有一个将保留工作的列表。而且只有一个生产商会在列表中添加工作。我有消费者(不止一个),正在等待从列表中获得工作……类似这样的事情……

制作人:

void AddJob(Job j)
{
    lock(qLock)
    {
        jobQ.Enqueue(j);
    }

    newJobEvent.Set(); // newJobEvent is AutoResetEvent
}

消费者

void Run()
{
    while(canRun)
    {
        newJobEvent.WaitOne();

        IJob job = null;

        lock(qLock)
        {
            job = jobQ.Dequeue();
        }

        // process job
    }
}

如果上述警告为真,那么如果我很快将两个作业加入队列,那么只有一个线程会获取该作业,不是吗?我假设 Set 将是原子的,即它执行以下操作:

  1. 设置事件
  2. 如果线程正在等待,选择一个线程唤醒
  3. 重置事件
  4. 运行选定的线程。

所以我基本上对 MSDN 中的警告感到困惑。这是一个有效的警告吗?

最佳答案

即使警告不是真的并且 Set 是原子的,你为什么要在这里使用 AutoResetEvent?假设您有一些生产者连续排队 3 个事件,并且有一个消费者。处理完第二个作业后,消费者会阻塞并且永远不会处理第三个作业。

我会使用 ReaderWriterLockSlim对于这种类型的同步。基本上,您需要多个生产者才能拥有写锁,但您不希望消费者在生产者仅读取队列大小时长时间锁定生产者。

关于c# - AutoResetEvent - 两次快速调用不能保证线程释放 - 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9493680/

相关文章:

c# - 模拟平面按钮鼠标 MouseDown 和 MouseOver

c# - onkeydown 类型的事件在服务器端有意义吗?

c++ - 字符串文字之间的比较

.net - SHCreateStreamOnFileEx 链接器错误

windows - 将 SetupDiSetDeviceRegistryProperty 与 SPDRP_HARDWAREID 结合使用

windows - 在 SYSTEMTIME 上执行算术运算

c# - Winforms WebBrowser嵌入Youtube视频

css - 对具有 "btn-normal"类的元素发出警告

android - 内部 Beta 测试应用在 Google Play 上显示警告消息

c# - 如何避免复制第 3 方 C++ dll?