我对并发编程比较陌生,正在尝试理解使用Monitor.Pulse和Monitor.Wait的好处。
MSDN的示例如下:
class MonitorSample
{
const int MAX_LOOP_TIME = 1000;
Queue m_smplQueue;
public MonitorSample()
{
m_smplQueue = new Queue();
}
public void FirstThread()
{
int counter = 0;
lock(m_smplQueue)
{
while(counter < MAX_LOOP_TIME)
{
//Wait, if the queue is busy.
Monitor.Wait(m_smplQueue);
//Push one element.
m_smplQueue.Enqueue(counter);
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
counter++;
}
}
}
public void SecondThread()
{
lock(m_smplQueue)
{
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
//Wait in the loop, while the queue is busy.
//Exit on the time-out when the first thread stops.
while(Monitor.Wait(m_smplQueue,1000))
{
//Pop the first element.
int counter = (int)m_smplQueue.Dequeue();
//Print the first element.
Console.WriteLine(counter.ToString());
//Release the waiting thread.
Monitor.Pulse(m_smplQueue);
}
}
}
//Return the number of queue elements.
public int GetQueueCount()
{
return m_smplQueue.Count;
}
static void Main(string[] args)
{
//Create the MonitorSample object.
MonitorSample test = new MonitorSample();
//Create the first thread.
Thread tFirst = new Thread(new ThreadStart(test.FirstThread));
//Create the second thread.
Thread tSecond = new Thread(new ThreadStart(test.SecondThread));
//Start threads.
tFirst.Start();
tSecond.Start();
//wait to the end of the two threads
tFirst.Join();
tSecond.Join();
//Print the number of queue elements.
Console.WriteLine("Queue Count = " + test.GetQueueCount().ToString());
}
}我看不出用Wait和Pulse代替这个有什么好处:
public void FirstThreadTwo()
{
int counter = 0;
while (counter < MAX_LOOP_TIME)
{
lock (m_smplQueue)
{
m_smplQueue.Enqueue(counter);
counter++;
}
}
}
public void SecondThreadTwo()
{
while (true)
{
lock (m_smplQueue)
{
int counter = (int)m_smplQueue.Dequeue();
Console.WriteLine(counter.ToString());
}
}
}任何帮助都是非常感谢的。谢谢
发布于 2011-07-05 04:28:48
要描述“优势”,一个关键问题是“超越什么?”如果您的意思是“优先于热循环”,那么,CPU利用率是显而易见的。如果你的意思是“优先于睡眠/重试循环”-你可以得到更快的响应(Pulse不需要等待很长时间),并且使用更低的CPU (你不需要不必要地唤醒2000次)。
不过,一般来说,人们的意思是“优先于Mutex等”。
我倾向于广泛地使用它们,甚至优先于互斥、重置事件等;原因:
lock来处理同步,所以,当我需要等待某些东西时,我很可能已经有了一个互斥锁(发布于 2011-07-05 04:28:19
您的代码片段中有一个严重的缺陷,当SecondThreadTwo()试图在空队列上调用Dequeue()时,它将严重失败。您可能是通过让FirstThreadTwo()在使用者线程之前执行一小段时间(可能是先启动它)才能让它工作。这是一个意外,在运行这些线程一段时间或使用不同的机器负载启动它们后,它将停止工作。这样可以意外地在相当长的一段时间内无差错地工作,很难诊断出偶尔的故障。
没有办法编写一个锁定算法来阻塞使用者,直到队列变为非空,只使用lock语句。一个不断进入和退出锁的繁忙循环是有效的,但它是一个非常糟糕的替代品。
编写这类代码最好留给线程专家,很难证明它在所有情况下都能工作。不只是没有像这样的失败模式或线程竞争。而且还具有避免死锁、活锁和线程护送的算法的一般适应性。在.NET的世界里,大师是Jeffrey Richter和Joe Duffy。他们把锁设计当做早餐吃,无论是在书中还是在博客和杂志文章中都是如此。窃取他们的代码是预期的,也是被接受的。并通过在System.Collections.Concurrent命名空间中的添加部分地进入.NET框架。
发布于 2011-07-05 04:20:42
正如您所猜测的那样,使用Monitor.Pulse/Wait可以提高性能。获取锁是一个相对昂贵的操作。通过使用Monitor.Wait,您的线程将处于休眠状态,直到其他线程通过“Monitor.Pulse”唤醒您的线程。
您将看到TaskManager中的不同之处,因为即使队列中没有任何内容,也会锁定一个处理器核心。
https://stackoverflow.com/questions/6575723
复制相似问题