2011-11-18 25 views
2

我正在看这个msdn关于与Monitor.Pulse()的线程同步的页面上的示例2。生产者 - 消费者示例,都在锁(此)块

Cell对象被创建并传递给生产者和消费者对象。

Cell cell = new Cell(); 
CellProd prod = new CellProd(cell, 20); 
CellCons cons = new CellCons(cell, 20); 

一个线程的每一个这两个

Thread producer = new Thread(new ThreadStart(prod.ThreadRun)); 
Thread consumer = new Thread(new ThreadStart(cons.ThreadRun)); 

创建的ThreadRun在每种情况下一个循环,调用Cell.ReadFromCell()或Cell.WriteToCell(),取决于消费者/生产者。例如,制作者这

public void ThreadRun() 
{ 
    for(int looper=1; looper<=quantity; looper++) 
    cell.WriteToCell(looper); // "producing" 
} 

我不明白的一点是,在每一种方法,他们开始用

lock(this) 

而且由于它是一样的Cell对象(即,上面的锁定语句中的'this')传递给两者,我一直以为只有一个线程可以在这段代码中。然而,从Monitor.Pulse()和Monitor.Wait()后面的代码看来,这两个线程同时在这些部分中。如果有人拥有该锁,并且击中了一个Monitor.Wait(),那么另一个线程就永远不会Pulse,因为它被阻塞等待锁定。

我猜测有一个简单的解决方案,我误解了一些东西,从我的测试运行代码它看起来像两个线程同时在他们的关键部分,所以锁(这)不是做我应该做的印象。

+5

请注意,这是一种糟糕的编程习惯来“锁定(this)”。相反,创建一个类型为object的私有字段并对其进行锁定。这是一个不好的做法,因为*任何人*都可以锁定该对象;如果您的锁定订单保证仅取决于*内部的代码*可以锁定的类型然后锁定这会使代码变得脆弱而难以分析。锁定私钥意味着你知道*只有*可以获得对私钥对象的引用的代码才能取出锁。 –

+2

Eric,我完全同意,但MSDN不应该首先提供这样的示例代码。大多数时候,人们使用'lock(this)'语句是因为他们认为如果它在MSDN上,它必须是正确的方法。有没有办法提交更新MSDN内容的请求? – SolutionYogi

+1

@SolutionYogi:好点。我会将其提请文档管理员注意。谢谢! –

回答

8

你缺少的东西是Monitor.Wait(this)版本锁在this直到它被唤醒。所以,是的,你的消费者线程看起来像就像它在锁,因此拥有它,但它真的暂时释放它。

the docs

当一个线程调用wait,它释放对象的锁并进入对象的等待队列。对象就绪队列中的下一个线程(如果有的话)获取该锁并独占使用该对象。所有调用Wait的线程都会保留在等待队列中,直到它们从锁的所有者发送的Pulse或PulseAll接收到一个信号。如果发送脉冲,则只有等待队列头部的线程受到影响。如果发送了PulseAll,则等待该对象的所有线程都会受到影响。当收到信号时,一个或多个线程离开等待队列并进入就绪队列。准备好的队列中的线程被允许重新获取锁。

+0

Ahhh很有意义,谢谢! –