11

console.writeとconsole.writelineを使用してロギングを提供するコンソールアプリケーションを作成しました。このアプリケーションは、通信に非同期のbeginacceptconnection()とbeginread()(ソケット)を使用するサーバーアプリケーションです。ときどき、ハングしているというレポートが表示され、限られたデバッグから、Console.Writeline()またはConsole.write()の問題を確認できます。

マルチスレッドであるため、ロギングクラスをロックするように注意しているので、一度に1つのスレッドだけがメッセージをログに記録できます。コントロールがConsole.Writeに渡され、それが戻るのを待っていること....それは決して行われません。

数日前に別の失敗の報告がありましたが、今回は起動中に非同期接続がまだ開始されていません(メインスレッドは起動するスレッドを生成します)。画像が送信されました。 ...以下を参照してください(これを防ぐために、開始と終了のクリティカルセクション行を追加しましたが、追加しませんでした)

// Logging Class

public class Logging
{
    // Lock to make the logging class thread safe.
    static readonly object _locker = new object();

    public delegate void msgHandlerWriteLineDelegate(string msg, Color col);
    public static event msgHandlerWriteLineDelegate themsgHandlerWriteLineDelegate;

    public delegate void msgHandlerWriteDelegate(string msg, Color col);
    public static event msgHandlerWriteDelegate themsgHandlerWriteDelegate;

    public static void Write(string a, Color Col)
    {
        if (themsgHandlerWriteDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteDelegate(a, Col);
            }
        }
    }

    public static void Write(string a)
    {
        if (themsgHandlerWriteDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteDelegate(a, Color.Black);
            }
        }
    }

    public static void WriteLine(string a, Color Col)
    {
        if (themsgHandlerWriteLineDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteLineDelegate(a, Col);
            }
        }
    }

    public static void WriteLine(string a)
    {
        if (themsgHandlerWriteLineDelegate != null)
        {
            lock (_locker)
            {
                themsgHandlerWriteLineDelegate(a, Color.Black);
            }
        }
    }

    // Console Methods That implement the delegates in my logging class.

    public static void ConsoleWriteLine(string message, Color Col)
    {
        try
        {
            if (Col == Color.Black)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
            }
            else
            {
                Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Col.Name);
            }
            Thread.BeginCriticalRegion();
            Console.WriteLine(message);
            Thread.EndCriticalRegion();
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    public static void ConsoleWrite(string message, Color Col)
    {
        try
        {
            if (Col == Color.Black)
            {
                Console.ForegroundColor = ConsoleColor.Gray;
            }
            else
            {
                Console.ForegroundColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), Col.Name);
            }
            Thread.BeginCriticalRegion();
            Console.Write(message);//**THIS IS WHERE IS HANGS...IT NEVER RETURNS **
            Thread.EndCriticalRegion();
            Console.ForegroundColor = ConsoleColor.Gray;
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    public static void ConsoleUpdate(string message)
    {
        try
        {
            Thread.BeginCriticalRegion();
            Console.WriteLine(message);//**THIS IS WHERE IS HANGS...IT NEVER RETURNS **
            Thread.EndCriticalRegion();
        }
        catch (ThreadAbortException ex)
        {
            Console.WriteLine("ThreadAbortException : " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception : " + ex.Message);
        }
    }

    // The main method...subscribes to delegates and spawns a thread to boot HW..main thread then exits.

    public static void Main()
    {
        Logging.themsgHandlerWriteDelegate += new Logging.msgHandlerWriteDelegate(ConsoleWrite);
        Logging.themsgHandlerWriteLineDelegate += new Logging.msgHandlerWriteLineDelegate(ConsoleWriteLine);
        Logging.themsgHandlerUpdateDelegate += new Logging.msgHandlerUpdateDelegate(ConsoleUpdate);
    }
}

public class ClassOnOtherThread
{
    // In a different class running on a different thread the following line occasionly invokes the error:

    private void BootHw(string Resource, string Resource2)
    {
        Logging.Write("\t\t[");
    }
}

私がMSDNを読んだところ、Console.WriteLineとConsole.Writeはスレッドセーフであるため、実際にはロックする必要はありません。Microsoftのコードが間違っているとは信じられません(;-)。エラーを作成するのは、私のコードが実行している何らかの相互作用であると推測します。

今私の質問:Console.WriteLineとConsole.Writeが中断されるのを防ぐために何かをする必要がありますか?...それが中断する何かがあると思います...しかし、私はそれを本当に知りません!!

どんな助けでも私は非常にありがたいです。

よろしく、

ゴードン。

4

4 に答える 4

8

私も同じ問題を抱えていました。

console.readkey()デバッグモードでアプリケーションを閉じるのを防ぐためにメインスレッドで使用していました。

それを無限ループに置き換えた後、私の問題は解決しました。

于 2012-09-11T13:52:19.990 に答える
2

これは少し長いショットですが、ToString()メソッドがロックを取得するオブジェクトを使用してConsole.WriteLineを呼び出しているのではないかと思います。その場合、Console.WriteLineによって内部的に取得されたロックに関してデッドロック状態になる可能性があります。

私はかつてこのバグレポートをMicrosoftConnectに投稿しましたが、残念ながら彼らはそれを修正することを拒否しました。

于 2011-06-27T22:17:20.750 に答える
2

ログの周りのロックを削除して、問題を解決する必要があります。ロギングはConsole.WriteLine、同期 (およびスレッドセーフ) を介して行われます。独自のロック メカニズムによってデッドロックが発生している可能性があります (ただし、コードを見ないと確認できません)。

于 2011-06-27T20:52:41.013 に答える
2

あなたのアプリケーションは、stderr と stdout をリダイレクトする別のプロセスによって開始されていると思います。「ウォッチャー」プロセスが同じスレッドの両方のストリームにReadToEnd()を使用すると、デッドロックする可能性があります。

デッドロックの別のオプションは、stdin を介して子プロセスの入力を送信することです。これにより、無期限に入力を待機するコンソールを持つ別のプロセスが開始されます。これは、stdinがリダイレクトされたときにブロックするwmic.exeで一度発生しました。

ログクラスで遊んだことがあるなら、基になる Console.Out の Stream を独自のものに変更しているのではないかと思います。何か分析できるように、少なくともアプリケーションがハングしているコールスタックを投稿してください。コンソール ストリームを自分のものに置き換えると、自分自身を撃つ方法がたくさんあります。

さようなら、アロイス・クラウス

于 2011-06-27T20:53:07.550 に答える