下面的代码是教授在课堂上提出的多线程示例 . 我是编码新手(第一门课程) . 我已阅读过多线程和使用锁 . 阅读理论很有趣 . var fun = Theory.Read(多线程);实际上编码线程和锁似乎让我感到困惑 .
试图理解下面代码中的两个线程将如何表现 . 从测试代码看起来看起来像lock1不会释放而message2没有被排队,但我可能错了 . 看起来存在同步问题 . 这是一个僵局的例子吗?我也想知道如果使用两个不同的队列,为什么需要锁和线程 . 我没有看到共享资源 . 有没有办法修复此代码以防止同步问题?
private static object Lock1 = new object(); // Protect MessageQueueOne
private static object Lock2 = new object(); // Protect MessageQueueTwo
private static Queue<string> MessageQueueOne = new Queue<string>();
private static Queue<string> MessageQueueTwo = new Queue<string>();
private static void AddMessages(string message1, string message2)
{
lock (Lock1)
{
// (1) Thread 1 is here...
MessageQueueOne.Enqueue(message1);
lock (Lock2)
{
MessageQueueTwo.Enqueue(message2);
}
}
}
private static void RemoveMessages()
{
lock (Lock2)
{
if (MessageQueueTwo.Count > 0)
{
// (2) Thread 2 is here...
Console.WriteLine(MessageQueueTwo.Dequeue());
}
lock (Lock1)
{
if (MessageQueueOne.Count > 0)
{
Console.WriteLine(MessageQueueOne.Dequeue());
}
}
}
}
private static void Main()
{
Task taskOne = Task.Run(() =>
{
for (int i = 0; i < 100; ++i)
{
AddMessages($"Message One: {DateTime.Now}", $"Message Two: {DateTime.UtcNow}");
Thread.Sleep(25);
}
});
Task taskTwo = Task.Run(() =>
{
for (int i = 0; i < 100; ++i)
{
RemoveMessages();
Thread.Sleep(25);
}
});
taskOne.Wait();
taskTwo.Wait();
Console.Write("Tasks are finished");
Console.ReadKey();
}
1 回答
帖子中的代码是死锁的经典示例,并且预计会在大多数情况下陷入僵局 . 请参阅Wikipedia有关死锁的文章中的更多链接 .
导致死锁的原因是:一个线程锁定“lock1”并等待“lock2”,另一个线程同时锁定“lock2”并在获取“lock1”后将释放它,这将永远不会被等待线程释放 .
标准解决方案
听你的 class 知道答案
阅读现有的例子
如果上述失败 - 一个选项是以固定顺序获取资源(即,如果需要锁定多个资源,则首先获得"lock1",而不是"lock2"等等)以获取所有线程(Would you explain lock ordering?) .