1

私はかなり標準的な設定をしています:

    void Run()
    {
        this.sw = File.CreateText(logfile)

        start.RedirectStandardInput = true;
        start.RedirectStandardOutput = true;
        start.RedirectStandardError = true;
        start.UseShellExecute = false;
        Process proc = Process.Start(start)
        proc.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
        proc.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
        proc.BeginOutputReadLine();
        proc.BeginErrorReadLine();
        ...
    }

    private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        if (!String.IsNullOrEmpty(outLine.Data))
        {
            sw.WriteLine(outLine.Data);
        }
    }

最初の試運転を行い、数分後に完全に実行した後、クラッシュするまで、すべてがうまく機能していると思いました。

未処理の例外: 未処理の例外: System.IndexOutOfRangeException: メモリのコピー中に I/O 競合状態が検出された可能性があります。デフォルトでは、I/O パッケージはスレッドセーフではありません。マルチスレッド アプリケーションでは、TextReader または T xtWriter の Synchronized メソッドによって返されるスレッド セーフなラッパーなど、スレッド セーフな方法でストリームにアクセスする必要があります。これは、StreamWriter や StreamReader などのクラスにも当てはまります。System.Buffer.InternalBlockCopy (配列 src、Int32 srcOffset、配列 dst、Int 32 dstOffset、Int32 カウント) で System.IO.StreamWriter.Write (Char[] バッファー、Int32 インデックス、Int32 カウント) で System.IO.TextWriter。 WriteLine(文字列値)

私は自分のアプリで単一のスレッドしか実行していないので、これが起こったと考えることができる唯一の方法は、stdout と stderror の両方が同時にイベントを発生させる場合です。

言及された「スレッドセーフラッパー」を実装するには、コードはどのように見えるべきですか?

4

2 に答える 2

1

WriteLine を持っているところはどこでも、次のようにその周りにロックを置きます

public class MyClass
{
   object myLockObject = new object();

   public void MyOperationCalledOnAnEvent(string data)
   {
      lock (myLockObject)
          sw.WriteLine(outLine.Data);
   } 

}
于 2013-01-11T12:49:42.367 に答える
1

これで問題が解決するはずです:

private readonly object _looker = new object();

private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
    {
        if (!String.IsNullOrEmpty(outLine.Data))
        {
            lock(_locker)
            {
                sw.WriteLine(outLine.Data);
            }
        }
    }

別の解決策として、たとえば に出力を追加しConcurrentQueue、別のスレッドでメッセージを取得してストリームに保存することができます。

于 2013-01-11T12:49:50.347 に答える