Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# C中线程的ProducerConsumerQueue中的竞争条件#_C#_Multithreading - Fatal编程技术网

C# C中线程的ProducerConsumerQueue中的竞争条件#

C# C中线程的ProducerConsumerQueue中的竞争条件#,c#,multithreading,C#,Multithreading,我认为ProducerConsumerQueuefrom . 代码如下: using System; using System.Threading; using System.Collections.Generic; class ProducerConsumerQueue : IDisposable { EventWaitHandle _wh = new AutoResetEvent (false); Thread _worker; readonly object _locker

我认为
ProducerConsumerQueue
from
. 代码如下:

using System;
using System.Threading;
using System.Collections.Generic;

class ProducerConsumerQueue : IDisposable
{
  EventWaitHandle _wh = new AutoResetEvent (false);
  Thread _worker;
  readonly object _locker = new object();
  Queue<string> _tasks = new Queue<string>();

  public ProducerConsumerQueue()
  {
    _worker = new Thread (Work);
    _worker.Start();
  }

  public void EnqueueTask (string task)
  {
    lock (_locker) _tasks.Enqueue (task);
    _wh.Set();
  }

  public void Dispose()
  {
    EnqueueTask (null);     // Signal the consumer to exit.
    _worker.Join();         // Wait for the consumer's thread to finish.
    _wh.Close();            // Release any OS resources.
  }

  void Work()
  {
    while (true)
    {
      string task = null;
      lock (_locker)
        if (_tasks.Count > 0)
        {
          task = _tasks.Dequeue();
          if (task == null) return;
        }
      if (task != null)
      {
        Console.WriteLine ("Performing task: " + task);
        Thread.Sleep (1000);  // simulate work...
      }
      else
        _wh.WaitOne();         // No more tasks - wait for a signal
    }
  }
}
t2:p调用
EnqueueItem(操作)


t3:C到达
\u wh.WaitOne()
并永远等待(假设生产者停止添加新值)

每次调用
EnqueueItem
都会做两件事-它首先确保队列中至少有一个项目(P1),然后在
自动resetEvent
(P2)上调用
Set

消费者在一个循环中执行三个活动-它尝试将一个项目(C1)出列,然后处理该项目(C2a)或等待
AutoResetEvent
被设置(C2b)

P1和C1是受锁保护的项,因此我们知道其中一项将出现在另一项之前,并且它们不会交错


C1要得出列表中没有项目的结论,P1必须出现在它之后。但是,因为我们知道P2会跟随,我们知道在将来的某个时间点,
AutoResetEvent
肯定会由P2设置,因此C2b等待将始终得到满足。

书中的错误?胡说从严肃的角度来看,生产者是您调用的
排队任务
。我不理解你的评论
t1
,你引用了消费者代码的和平,说生产者。
Work
消耗队列,任何调用
EnqueueTask
的人都将生成项目。工作循环仅在null任务排队时退出,并且通常应位于最后一行等待Set事件。但我同意,分支的数量和对null的推理在消费者循环中看起来相当不恰当。当然,在生产代码中,我们会使用更可靠的机制,如
ConcurrentQueue
。为什么代码会在
处“永远等待”\u wh.WaitOne()
?调用
EnqueueItem(action)
的代码将在某个时候调用
\u wh.Set()
。此外,正如其他注释所暗示的,您的术语似乎是倒退的。producer是生成(“producer”)任务并将其添加到队列中的代码,即调用
EnqueueTask
的代码。使用者是从队列中提取任务并“使用”它们的代码。这种逆转尤其明显,在问题末尾的插入语中,你说“消费者停止生产”这应该是一个警告,说明您使用的术语不正确。如果
EnqueueAction
在到达
t3
之前已完成运行,则事件已
Set
WaitOne
不会等待。
lock (_locker)
        if (_tasks.Count > 0)