1

尝试从锁定部分调用 Console.WriteLine,但似乎无法正常工作 - 控制台未锁定。下面是简单应用程序的代码 - 两个线程并行填充一个列表,出于调试目的,我正在打印有关线程工作和新添加元素的信息。

using System;
using System.Threading;
using System.Collections.Generic;

class ThreadSafe
{
    static object SyncRoot = new object();

    static int threadsCount = 0;
    static List<string> list = new List<string>();

    static void Main()
    {
        Thread t1 = new Thread(AddItems);
        Thread t2 = new Thread(AddItems);
        t1.Start();
        t2.Start();

        t1.Join();
        t2.Join();

        PrintItems();

        Console.ReadLine();
    }

    static void PrintItems()
    {
        string[] items;

        Console.WriteLine("Converting list to array...");
        items = list.ToArray();

        Console.WriteLine("Printing array...");
        foreach (string s in items)
            Console.WriteLine(s);
    }

    static void AddItems()
    {
        int threadNo = threadsCount;
        threadsCount++;


        {
            Console.WriteLine("Populating list from {0} item in thread N {1}...", list.Count, threadNo);
            for (int i = 0; i < 50; i++)
            {
                lock (SyncRoot)
                {
                    Console.Write("Population. Thread N {0} is running. ", threadNo);
                    Console.WriteLine("Element N {0} has been added successfully.", list.Count);
                    list.Add("Item " + list.Count);
                }
            }
        }
    }
}

结果:

Populating list from 0 item in thread N 1...
Population. Thread N 1 is running. Element N 0 has been added successfully.
Population. Thread N 1 is running. Element N 1 has been added successfully.
Population. Thread N 1 is running. Element N 2 has been added successfully.
Population. Thread N 1 is running. Element N 3 has been added successfully.
Population. Thread N 1 is running. Element N 4 has been added successfully.
Population. Thread N 1 is running. Element N 5 has been added successfully.
Population. Thread N 1 is running. Element N 6 has been added successfully.
Population. Thread N 1 is running. Element N 7 has been added successfully.
Population. Thread N 1 is running. Element N 8 has been added successfully.
Population. Thread N 1 is running. Element N 9 has been added successfully.
Population. Thread N 1 is running. Element N 10 has been added successfully.
Population. Thread N 1 is running. Element N 11 has been added successfully.
Population. Thread N 1 is running. Element N 12 has been added successfully.
Population. Thread N 1 is running. Element N 13 has been added successfully.
Population. Thread N 1 is running. Element N 14 has been added successfully.
Population. Thread N 1 is running. Element N 15 has been added successfully.
Population. Thread N 1 is running. Populating list from 0 item in thread N 0...
Element N 16 has been added successfully.
Population. Thread N 0 is running. Element N 17 has been added successfully.
Population. Thread N 0 is running. Element N 18 has been added successfully.
Population. Thread N 0 is running. Element N 19 has been added successfully.

在第 15 步和第 16 步之间,新的第一个开始运行并在锁定部分中的 Console.Write 和 Console.WriteLine 调用之间输出其内容... Console.WriteLine 确实是非线程安全的吗?或者我做错了什么?

谢谢!

4

4 回答 4

4

您有 2 个AddItems线程,每个线程都进行解锁输出(函数中的第一个)。这种交错是预期的行为。你需要:

  lock (SyncRoot)
  {
    Console.WriteLine("Populating list from {0} item in thread N {1}...", list.Count, threadNo); 
  }
于 2012-05-08T13:33:49.700 回答
2

该行:

Console.WriteLine("Populating list from {0} item in thread N {1}...", list.Count, threadNo);

出现在同步块之外。

于 2012-05-08T13:33:57.813 回答
1

您的某些代码位于锁定部分之外。第一件事:

int threadNo = threadsCount;
        threadsCount++;

不是线程安全的。想象一个线程在增加线程计数之前启动并被第二个线程中断。两个线程都会有threadNo = 0

但这在这里似乎不是问题,尽管如果您使用它进行一些计算可能会导致问题。

正如其他人指出的那样:您还需要锁定 Console.WriteLine("Populating list from {0} item in thread N {1}...", list.Count, threadNo);,因此当下一个线程启动时,它会等待在控制台上写入,而另一个线程也在写入。

于 2012-05-08T13:55:39.780 回答
0

Console.WriteLine("从线程 N {1} 中的 {0} 项填充列表...", list.Count, threadNo); 不在锁定区域内,因此可以随时打印,如您所见。

于 2012-05-08T13:35:02.817 回答