10

Console.ReadKey()マルチスレッド プログラムで使用すると、奇妙な問題が発生します。

私の質問は次のとおりです。なぜこれが起こっているのですか?それはバグですか、それとも私が悪用しているためConsoleですか? (ドキュメントによると、コンソールはスレッドセーフであると想定されていることに注意してください。)

これをコードで説明するのが最も簡単です。

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("X");  // Also try with this line commented out.
            Task.Factory.StartNew(test);
            Console.ReadKey();
        }

        private static void test()
        {
            Console.WriteLine("Entering the test() function.");
            Thread.Sleep(1000);
            Console.WriteLine("Exiting the test() function.");
        }
    }
}

キーを押さに実行すると、何が表示されると思いますか?

答えはまさにあなたが期待するものです:

X
Entering the test() function.
Exiting the test() function.

をコメントアウトして、Console.WriteLine("X")もう一度実行します (キーを押さずに)。この出力が表示されることを期待していました:

Entering the test() function.
Exiting the test() function.

代わりに、何も見えません。次に、キーを押すと、次のように表示されます。

Entering the test() function.

...以上です。プログラムは (もちろん) 終了し、次の に進む時間がありませんWriteLine()

この行動はとても神秘的だと思います。回避するのは簡単ですが、なぜそれが起こるのか興味があります。

[編集]

Thread.Sleep(1)直前に追加するとConsole.ReadKey()、期待どおりに機能します。もちろん、Console.ReadKey()とにかく永遠に待機する必要があるため、これは必要ありません。

ある種の競合状態のように見えますか?

詳細情報: Servy は、Console.WriteLine("Entering the test() function.")いずれかのキーが押されるまで回線がブロックされていることを発見しました (私も複製しました)。

ビルド構成

Visual Studio 2012、Windows 7 x64、クアッド コア、英語 (英国)。

.Net4、.Net4.5、x86、AnyCPU、およびデバッグとリリースのすべての組み合わせを試しましたが、どれも私の PC では機能しません。しかし、本当に奇妙なことが起こりました。.Net4 用の AnyCPU バージョンを最初に試したときに動作し始めましたが、再び動作しなくなりました。一部のシステムにのみ影響する競合状態に非常によく似ています。

4

4 に答える 4

19

これは競合状態です。最初の Console.WriteLine がない場合は次のようになります。

  1. タスクは作成されますが、実行されません
  2. Console.ReadKey が実行され、Console.InternalSyncObject がロックされ、入力待ちがブロックされます。
  3. タスクの Console.WriteLine は Console.Out を呼び出します。Console.Out は、初回の初期化のために Console.InitializeStdOutError を呼び出して、コンソール ストリームをセットアップします。
  4. Console.InitializeStdOutError は Console.InternalSyncObject をロックしようとしますが、Console.ReadKey は既にそれを持っているため、ブロックされます。
  5. ユーザーがキーを押すと Console.ReadKey が返され、ロックが解除されます
  6. Console.WriteLine への呼び出しがブロック解除され、実行が終了します
  7. ReadKey 呼び出しの後に Main に何もないため、プロセスは終了します。
  8. タスク内の残りのコードを実行する機会がありません

Console.WriteLine がそこに残っている場合に動作が異なる理由は、Console.InitializeStdOutError への呼び出しが Console.ReadKey と並行して行われていないためです。

したがって、簡単な答えは次のとおりです。はい、コンソールを悪用しています。(Console.Out を逆参照して) 自分でコンソールを初期化するか、タスクの開始後、ReadKey の前にイベントを待機し、Console.WriteLine を初めて呼び出した後にタスクにイベントを通知させることができます。

于 2013-02-28T20:06:22.767 に答える
5

.NET 4.5 の内部バグとして確認されています。たとえば、ここで報告されています: https://connect.microsoft.com/VisualStudio/feedback/details/778650/undocumented-locking-behaviour-in-system-console

これは、.NET 3.5 および .NET 4 で機能しました。

詳細: http://blogs.microsoft.co.il/blogs/dorony/archive/2012/09/12/console-readkey-net-4-5-changes-may-deadlock-your-system.aspx

簡単な回避策を使用して、内部構造を初期化し、ブロックを回避できます。これを最初に追加するだけです(@renesteinから):

Console.Error.WriteLine(); 
Console.WriteLine(); 
于 2013-04-22T13:55:24.197 に答える
0

これは、マルチスレッドであるため、おそらく発生しています。非同期タスクが報告する機会を得る前に、メインスレッドが進行して終了しています。メイン スレッドが終了すると、すべての子スレッドが強制終了されます。

ReadKey の前に待機を配置するとどうなりますか? 正しく出力されていますか?

于 2013-02-28T19:27:46.740 に答える