2

複数のスレッドからファイルにログを記録しているときに、競合状態のように見えるものがあります。

1) アプリケーションの複数のスレッドで共有されるカスタム ロガー クラス (ConfigurableTraceLogger) があります。メインコア関数をすべて呼び出すラッパー関数がたくさんあります

protected void TraceData(String category, TraceEventType type, EventId id, string prefix, string format)
{
    foreach (TraceListener item in _listeners)
    {
        IConfigurableTraceListener cl = item as IConfigurableTraceListener;

        if (cl != null && cl.Category == category.ToLower())
        {

            if (DisplayMethodName)
                item.TraceData(new TraceEventCache(), _instanceName, type, (int)id, prefix + format);
            else
                item.TraceData(new TraceEventCache(), _instanceName, type, (int)id, format);

            item.Flush();
        }
    }
}

ご覧のとおり、私のクラスは、TraceListner から派生したさまざまなクラスをコレクション _listeners に格納するだけです。基本的に、コンソールとテキスト ファイル リスナーのみがあります。TraceData の機能 カテゴリ名 (つまり、ログの開始) を取得し、適切なリスナーを見つけます。すべてのリスナーは構成ファイル名で定義されます

これで、コレクションにカスタム リスナーも追加されました

public class ConfigurableTextWriterTraceListener : TextWriterTraceListener, IConfigurableTraceListener

そのカスタム クラスは、1 つのプロパティを除いて何もオーバーライドしません。

protected override string[] GetSupportedAttributes()
{
    return new string[] { "category" };
}

5 ~ 10 分後にアプリケーションを開始すると、通話で例外が発生します

           item.TraceData(new TraceEventCache(), _instanceName, type, (int)id, prefix + format);

例外は言っています:

「メモリのコピー中に I/O 競合状態の可能性が検出されました。I/O パッケージはデフォルトではスレッド セーフではありません。マルチスレッド アプリケーションでは、TextReader によって返されるスレッド セーフ ラッパーなど、スレッド セーフな方法でストリームにアクセスする必要があります。または TextWriter の Synchronized メソッド。これは、StreamWriter や StreamReader などのクラスにも適用されます。」

その後、同じ呼び出しで2番目の例外を何度も取得し続けます

item.TraceData(new TraceEventCache(), _instanceName, type, (int)id, prefix + format);

例外

カウントを 0 未満にすることはできません。パラメータ名: count スタック トレース: " at System.String.CopyTo(Int32 sourceIndex, Char[] destination, Int32 destinationIndex, Int32 count)\r\n at System.IO.StreamWriter.Write(String value)\r\n at System.IO.StreamWriter.Write(String value) System.Diagnostics.TextWriterTraceListener.Write(String message)\r\n System.Diagnostics.TraceListener.WriteHeader(String source, TraceEventType eventType, Int32 id)\r\n at System.Diagnostics.TraceListener.TraceData(TraceEventCache eventCache, String) source, TraceEventType eventType, Int32 id, Object data)\r\n at Jfc.Configuration.ConfigurableTraceLogger.TraceData(String category, TraceEventType type, EventId id, String prefix, String format, Object[] args)"

私のクラスはTraceDataへの呼び出しと同様にスレッドセーフではないようです。しかし ConfigurableTextWriterTraceListener は結局スレッドセーフと言われています。ただし、実行時に TextWriterTraceListener 派生クラスの IsThreadSafe プロパティをチェックしたところ、false でした。問題がどこにあるのかを理解しようとしています。

4

1 に答える 1

1

つまり、TraceListener はスレッド セーフではなく、複数のスレッドからアクセスすると壊れます。リスナーをスレッド セーフにするか、1 つのスレッドだけが特定のインスタンスにアクセスするようにする方法を見つける必要があります。

それらをスレッドセーフにする 1 つの方法は、同期キューを使用して、すべての呼び出しでデータ項目をキューにエンキューし、「実際の」traceListener がデータ項目をデキューして別のスレッドに書き出すことです。

また、リスナーの辞書にも注意する必要があります。辞書の更新はスレッドセーフではありませんが、最後の更新が適用される前に辞書にアクセスしない場合は、そのままにしておくことができます

于 2009-11-09T16:16:49.353 に答える