锁定的console.writeline调用工作不正确

时间:2012-05-08 13:28:59

标签: c# multithreading io thread-safety console.writeline

尝试从锁定部分调用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 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:2)

该行:

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

出现在synchronized块之外。

答案 2 :(得分:1)

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

int threadNo = threadsCount;
        threadsCount++;

不是线程安全的。想象一下,线程启动并被第二个线程中断,然后才能增加线程数。然后两个线程都有threadNo = 0

但这似乎不是一个问题,虽然如果你使用它会导致问题做一些计算。

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

答案 3 :(得分:0)

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