// DeadLockSample.cs
// 分析一下为什么会发生死锁?
using System;
using System.Threading;
public class Test
{
static readonly object firstLock = new object();
static readonly object secondLock = new object();
static void Main()
{
new Thread(new ThreadStart(ThreadJob)).Start();
// Wait until we're fairly sure the other thread
// has grabbed firstLock
Thread.Sleep(500);
Console.WriteLine ("Locking secondLock");
lock (secondLock)
{
Console.WriteLine ("Locked secondLock");
Console.WriteLine ("Locking firstLock");
lock (firstLock)
{
Console.WriteLine ("Locked firstLock");
}
Console.WriteLine ("Released firstLock");
}
Console.WriteLine("Released secondLock");
}
static void ThreadJob()
{
Console.WriteLine ("\t\t\t\tLocking firstLock");
lock (firstLock)
{
Console.WriteLine("\t\t\t\tLocked firstLock");
// Wait until we're fairly sure the first thread
// has grabbed secondLock
Thread.Sleep(1000);
Console.WriteLine("\t\t\t\tLocking secondLock");
lock (secondLock)
{
Console.WriteLine("\t\t\t\tLocked secondLock");
}
Console.WriteLine ("\t\t\t\tReleased secondLock");
}
Console.WriteLine("\t\t\t\tReleased firstLock");
}
}
Locking firstLock
Locked firstLock
Locking secondLock
Locked secondLock
Locking firstLock
Locking secondLock
因应之道,使用Queue和Monitor:
//QueueMonitorThread.cs
using System;
using System.Collections;
using System.Threading;
public class Test
{
static ProducerConsumer queue;
static void Main()
{
queue = new ProducerConsumer();
new Thread(new ThreadStart(ConsumerJob)).Start();
Random rng = new Random(0);
for (int i=0; i < 10; i++)
{
Console.WriteLine ("Producing {0}", i);
queue.Produce(i);
Thread.Sleep(rng.Next(1000));
}
}
static void ConsumerJob()
{
// Make sure we get a different random seed from the
// first thread
Random rng = new Random(1);
// We happen to know we've only got 10
// items to receive
for (int i=0; i < 10; i++)
{
object o = queue.Consume();
Console.WriteLine ("\t\t\t\tConsuming {0}", o);
Thread.Sleep(rng.Next(1000));
}
}
}
public class ProducerConsumer
{
readonly object listLock = new object();
Queue queue = new Queue();
public void Produce(object o)
{
lock (listLock)
{
queue.Enqueue(o);
if (queue.Count==1)
{
Monitor.Pulse(listLock);
}
}
}
public object Consume()
{
lock (listLock)
{
while (queue.Count==0)
{
Monitor.Wait(listLock);
}
return queue.Dequeue();
}
}
}
Producing 0
Consuming 0
Producing 1
Consuming 1
Producing 2
Consuming 2
Producing 3
Consuming 3
Producing 4
Producing 5
Consuming 4
Producing 6
Consuming 5
Consuming 6
Producing 7
Consuming 7
Producing 8
Consuming 8
Producing 9
Consuming 9