C# AutoResetEvent-两个set调用不会很快发生';不能保证线程释放-为什么?

C# AutoResetEvent-两个set调用不会很快发生';不能保证线程释放-为什么?,c#,warnings,msdn,autoresetevent,C#,Warnings,Msdn,Autoresetevent,我正在阅读MSDN上的AutoResetEvent文档,下面的警告让我有点烦 “重要: 无法保证对Set方法的每次调用都会释放一个线程。如果两个调用距离太近,因此在释放线程之前发生第二个调用,则只释放一个线程。这就好像第二个调用没有发生一样。此外,如果在没有线程等待且AutoResetEvent已为sig的情况下调用Set但是,电话没有任何效果。” 但是这个警告基本上扼杀了使用这种线程同步技术的理由。例如,我有一个可以保存工作的列表。而且只有一家生产商会在名单上增加工作岗位。我有很多消费者(不止

我正在阅读MSDN上的AutoResetEvent文档,下面的警告让我有点烦

“重要: 无法保证对Set方法的每次调用都会释放一个线程。如果两个调用距离太近,因此在释放线程之前发生第二个调用,则只释放一个线程。这就好像第二个调用没有发生一样。此外,如果在没有线程等待且AutoResetEvent已为sig的情况下调用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
    }
}
如果上面的警告是真的,那么如果我很快将两个作业排队,那么只有一个线程将拾取作业,不是吗?我假设集合将是原子的,也就是说,它会执行以下操作:

  • 设置事件
  • 如果线程正在等待,请选择一个线程进行唤醒
  • 重置事件
  • 运行所选线程

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

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


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

    即使警告不正确且设置为原子,您为什么要在此处使用AutoResetEvent?假设您有一些生产者将3个事件排成一行,并且有一个消费者。在处理第二个作业后,使用者将阻止并永远不会处理第三个作业


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

    MSDN上的消息确实是有效的消息。内部发生的事情是这样的:

  • 线程A等待事件
  • 线程B设置事件
  • [如果线程A处于自旋锁中]
  • [是]线程a检测到事件已设置,将其取消设置并恢复其工作
  • [否]事件将通知线程A唤醒,一旦唤醒,线程A将取消事件的设置并恢复其工作
  • 请注意,内部逻辑不是同步的,因为线程B不会等待线程A继续其业务。您可以通过引入一个临时的ManualResetEvent来实现同步,线程a在继续工作时必须发出信号,线程B必须等待该事件。由于windows线程模型的内部工作,默认情况下不会执行此操作。我猜文档有误导性,但是说Set方法只释放一个或多个等待线程是正确的


    或者,我建议您查看.NET 4.0中引入的BCL的System.Collections.Concurrent命名空间中的BlockingCollection类,它完全执行您试图执行的操作

    MSDN上的消息确实是一条有效消息。内部发生的事情是这样的:

  • 线程A等待事件
  • 线程B设置事件
  • [如果线程A处于自旋锁中]
  • [是]线程a检测到事件已设置,将其取消设置并恢复其工作
  • [否]事件将通知线程A唤醒,一旦唤醒,线程A将取消事件的设置并恢复其工作
  • 请注意,内部逻辑不是同步的,因为线程B不会等待线程A继续其业务。您可以通过引入一个临时的ManualResetEvent来实现同步,线程a在继续工作时必须发出信号,线程B必须等待该事件。由于windows线程模型的内部工作,默认情况下不会执行此操作。我猜文档有误导性,但是说Set方法只释放一个或多个等待线程是正确的


    或者,我建议您查看.NET 4.0中引入的BCL的System.Collections.Concurrent命名空间中的BlockingCollection类,它完全执行您正在尝试执行的操作

    是的,此代码只能在意外情况下正常工作。不要发明这个轮子,谷歌“c#producer-consumer queue”搜索大量样本。我在搜索中发现的大多数producer-consumer都使用等待/信号方法。这种方法的问题在于,当我想让员工辞职时,我必须提交虚拟工作。但如果我可以使用事件,我就可以让工人等待两个事件。一个用于作业,另一个用于关闭。感觉更干净。是的,这个代码只能在意外情况下正常工作。不要发明这个轮子,谷歌“c#producer-consumer queue”搜索大量样本。我在搜索中发现的大多数producer-consumer都使用等待/信号方法。这种方法的问题在于,当我想让员工辞职时,我必须提交虚拟工作。但如果我可以使用事件,我就可以让工人等待两个事件。一个用于作业,另一个用于关闭。那感觉更干净。。