c#包含队列锁定的多线程

时间:2017-04-17 05:46:53

标签: c# multithreading synchronization locks

以下代码是教授在课堂上提供的多线程示例。我是编码新手(第一门课程)。我已阅读过多线程和使用锁。阅读理论很有趣。 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 个答案:

答案 0 :(得分:0)

帖子中的代码是死锁的经典示例,并且预计会在大多数情况下死锁。请参阅Wikipedia有关死锁的文章中的更多链接。

导致死锁的原因:一个线程锁定“lock1”并等待“lock2”,另一个线程同时锁定“lock2”并在获取“lock1”后释放它,这将永远不会被等待释放线程。

标准解决方案

  • 听你的班级知道答案
  • 阅读现有的例子
  • 如果上述失败 - 一个选项是以固定顺序获取资源(即,如果需要锁定多个资源,则首先获取“lock1”,而不是“lock2”等等)以获取所有线程(Would you explain lock ordering? )。