1

ロックされたセクションからConsole.WriteLineを呼び出そうとしましたが、正しく機能していないようです-コンソールはロックされていません。以下は単純なアプリのコードです。2つのスレッドが並行してリストに入力されます。デバッグの目的で、スレッドの動作と新しく追加された要素に関する情報を出力しています。

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

AddItemsそれぞれがロックされていない出力を作成する2 つのスレッドがあります (関数の最初のスレッド)。このインターリーブは予期される動作です。必要なもの:

  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++;

スレッドセーフではありません。スレッドカウントをインクリメントする前に、スレッドが開始され、2 番目のスレッドによって中断されると想像してください。両方のスレッドは、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 に答える