2017-12-15 15 views
-1

StackBufferがスタックセーフではなく、複数のスレッドからアクセス(読み書き)されたときにロックされるべきである:herehere,here。 StringBuilderのインスタンスをロックする方法、特に追加するロックの数と場所については不明です。StringBuilderが正しくロックされてArgumentOutOfRangeExceptionがスローされないようにする方法

私は、次のコード(スニペット-ED)を持っている:

class MemoryTracker 
    { 
     private Process extProc { get; set; } 
     private StringBuilder sb { get; set; } 

     internal int trackByIP(string ip) 
     { 
      ... 
      ... 
      sb = new StringBuilder(); 
      extProc.OutputDataReceived += new DataReceivedEventHandler((s, e) => sb.Append(e.Data + "\n")); 
      extProc.ErrorDataReceived += new DataReceivedEventHandler((s, e) => sb.Append(e.Data + "\n")); 

      extProc.Start(); 
      extProc.PriorityClass  = ProcessPriorityClass.RealTime; 
      ... 
      ... 
     } 

     string getDataWStartEndPttrn(StringBuilder data, string strPttr, string endPttr, string extendedTerminator) 
     { 
      string s = data.ToString(); // <-- THROWS ArgumentOutOfRangeException 

      int si = getStartIdx(s, strPttr, patternDiff(strPttr, endPttr)); 
      int se = getEndIdx(s, endPttr, patternDiff(endPttr, strPttr)); 

      if (se >= 0 && si >= 0) 
      { 
       string s1 = s.Substring(si, se - si); 

       string sTMP = s.Substring(se); 
       string s2 = s.Substring(se, sTMP.IndexOf(extendedTerminator)); 

       return s1 + s2; 
      } 

      return ""; 
     } 

は、私はまだ同じエラーがスロー参照ロックを置きました。

class MemoryTracker 
{ 
    private Process extProc { get; set; } 
    private StringBuilder sb { get; set; } 
    private Object thisLock = new Object(); 


    string getDataWStartEndPttrn(StringBuilder data, string strPttr, string endPttr, string extendedTerminator) 
    { 
     lock (thisLock) 
     { 
      string s = data.ToString() ; // <-- STILL THROWS ArgumentOutOfRangeException 
     } 
... 
... 

QUESTION:どのように私は正しくロック/ロックをどこに配置するかについて考えますか?そこで私は、明示的にスレッドを作成しない場所ではありませんので、私はそれではなく、現在のそれを使用StringBuilderの周りスレッドセーフラッパーを作成StringBuilder.toString();

+3

また、2つの 'sb.Append'文をロックする必要があります。 – Evk

+0

これは、ロックの間違った使用です。あなたは特定のオブジェクトの使用の周りにロックします。この場合、文字列ビルダーをロックする必要があります。文字列ビルダーをパラメータとして渡しているように見えます。これは、ロックが別のスレッドによってアクセスされないようにすることを意味します。 (通常はsbの内容を変更するもの) – Hack

+0

ありがとう、私の考えは、おそらくappend()と.toString()の両方の呼び出しをロックするべきだったということでした。しかし、おそらく1つで十分です(追加のために)? –

答えて

3

代替ソリューションのスレッドセーフな使い方

だろうと想定しました。これにより、ラッパークラス内の同期ロジックがカプセル化されます。私は、StringBuilderクラスを使用するメソッドをロックするのではなく、この方法で少し上手くいくと思います。

ReaderWriteLockSlimを使用してください。これは、読み取りロックが要求されたときに複数のスレッドがコードブロックにアクセスできるようにします。単純に複数のスレッドが.ToString()メソッドを使用しようとすると、これは問題ありません。また、meanwile他のスレッドが.Append()を使いこなそうとすると、このスレッドはread(.ToString())の他のスレッドをすべて待ちます。

ここでは非常に基本的なインプットですが、それは良い出発点でなければなりません。

これで、スレッドセーフラッパーをどこにでも同期させる必要がなくなりました。

EDIT2017-12-18:コメントからの提案。いくつかのperfを実行する必要があります。テスト。シンプルなシナリオでは、lock statementがより適切です(最悪の場合は、読み書きするスレッドの数など、最善のケースをチェック...など)。コードに関しては、try、finnalyステートメントをロックステートメントに置き換えてください。.Append().ToString()の両方のロックは同じオブジェクトでロックされるはずです。

+0

ReaderWriterLockは、読み上げに多大な競合があり、書き方がほとんどない場合にのみ効率的です。 OPのシナリオでは、ロックがよりよく実行され、複雑さが少なくなることはほぼ確実です。 –

+0

おかげでVasil、それも同様に選択肢を知っていいです。 –

+0

@KevinGosse、あなたは正しいです。あなたの提案を含めるための編集を追加しました。 –

関連する問題