受到信号量小书的启发,我决定使用信号量实现Producer-Consumer问题。
我特别希望能够随意停止所有工作线程。 我已经广泛地测试了我的方法,并且找不到任何有问题的东西。
以下代码是测试的原型,可以作为控制台应用程序运行:
using System;
using System.Collections.Concurrent;
using System.Threading;
using NUnit.Framework;
public class ProducerConsumer
{
private static readonly int _numThreads = 5;
private static readonly int _numItemsEnqueued = 10;
private static readonly Semaphore _workItems = new Semaphore(0, int.MaxValue);
private static readonly ManualResetEvent _stop = new ManualResetEvent(false);
private static ConcurrentQueue<int> _queue;
public static void Main()
{
_queue = new ConcurrentQueue<int>();
// Create and start threads.
for (int i = 1; i <= _numThreads; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(Worker));
// Start the thread, passing the number.
t.Start(i);
}
// Wait for half a second, to allow all the
// threads to start and to block on the semaphore.
Thread.Sleep(500);
Console.WriteLine(string.Format("Main thread adds {0} items to the queue and calls Release() {0} times.", _numItemsEnqueued));
for (int i = 1; i <= _numItemsEnqueued; i++)
{
Console.WriteLine("Waking up a worker thread.");
_queue.Enqueue(i);
_workItems.Release(); //wake up 1 worker
Thread.Sleep(2000); //sleep 2 sec so it's clear the threads get unblocked 1 by 1
}
// sleep for 5 seconds to allow threads to exit
Thread.Sleep(5000);
Assert.True(_queue.Count == 0);
Console.WriteLine("Main thread stops all threads.");
_stop.Set();
// wait a while to exit
Thread.Sleep(5000);
Console.WriteLine("Main thread exits.");
Console.WriteLine(string.Format("Last value of Semaphore was {0}.", _workItems.Release()));
Assert.True(_queue.Count == 0);
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
private static void Worker(object num)
{
// Each worker thread begins by requesting the semaphore.
Console.WriteLine("Thread {0} begins and waits for the semaphore.", num);
WaitHandle[] wait = { _workItems, _stop };
int signal;
while (0 == (signal = WaitHandle.WaitAny(wait)))
{
Console.WriteLine("Thread {0} becomes unblocked by Release() and has work to do.", num);
int res;
if (_queue.TryDequeue(out res))
{
Console.WriteLine("Thread {0} dequeues {1}.", num, res);
}
else
{
throw new Exception("this should not happen.");
}
}
if (signal == 1)
Console.WriteLine("Thread {0} was stopped.", num);
Console.WriteLine("Thread {0} exits.", num);
}
}
现在对于我的问题,我假设当我在信号量上调用WaitHandle.WaitAny(semaphore)
时,我只使用Release()
将被唤醒。但是,我在文档中找不到这确实是真的。任何人都可以证实这是真的吗?
答案 0 :(得分:2)
确实很有意思的是,文档似乎没有明确说明在WaitOne
的情况下只有1个线程会收到信号。当你熟悉多线程理论时,这就变得不言而喻了。
是的,WaitOne
上调用的Semaphore
(以及包含WaitAny
的{{1}}列表中调用的WaitHandle
)一个线程。如果您希望从MSDN引用,那么Semaphore
是Semaphore
的子类,which is:
封装等待独占访问共享资源的特定于操作系统的对象。
是的,除非明确声明的方法提供独占访问权。
例如,WaitHandle
的方法WaitOne
将为所有等待的帖子but documentation is explicit about it取消阻止:
通知一个或多个等待线程发生了一个事件。