2017-01-16 20 views
0

循環バッファクラスを作成し、2つの異なるスレッドからアクセスする必要があります。循環バッファは2次元配列を使用し、1次元は行数、もう1つは浮動小数点配列の要素(2048)を使用します。ユーザーインターフェイススレッドは、任意の時点ですべての行を配列から読み取ることができます。バックグラウンドスレッドは、この配列に挿入する必要のある2048個の浮動小数点数を取得するTCPサーバースレッドです。ここでそれでユーザーインターフェーススレッドがすべての行を取得するコード循環バッファはスレッドセーフですか?もしそうでなければ、どうすればいいのですか?

static class CircularArrayBuffer 
    { 

    static float[,] buffer; 
    static int columns, rows; 
    static int nextFree = 0; 

    public static void CreateBuffer(int _columns, int _rows) 
    { 
     columns = _columns; 
     rows = _rows; 

     buffer = new float[rows,columns]; 
     nextFree = 0;  //reset pointer to first free buffer 
    } 

    public static float[] GetData(int index) 
    { 
     if (index > rows) 
     { 
      throw new System.ArgumentException("Index cannot be more than rows", "index"); 
     } 

     float[] rowArray = new float[columns]; 

     Buffer.BlockCopy(buffer, (((nextFree - 1 + index) % rows) * 4 * columns), rowArray, 0, columns * 4); //takes 2 microseconds! 

     return rowArray; 
    }  

    public static void AddData(float[] rowArray) //number of columns must be set! 
    { 
     if (rowArray.Count() > columns) 
     { 
      throw new System.ArgumentException("Data length cannot be more than number of columns", "columns"); 
     } 

     Buffer.BlockCopy(rowArray, 0, buffer, nextFree * 4 * columns, columns * 4); 
     nextFree = (nextFree + 1) % rows; 
    } 
} 

ある50msごとかそこら背景TCPサーバは、1行毎に50ミリ秒程度を添加することにします。ユーザーインターフェイススレッドは、実際にはOpenGLのOnRenderコールバックです。私はこのクラスの問題にぶつかりますか?もしそうなら、それを避ける方法は? ありがとう、Tom

+1

なぜすべて静的なのですか?それは意図的なのでしょうか? – CodingYoshi

+0

パフォーマンスの理由のみ。それが本当に必要なのか分からない。 – Tom

+0

このコードを慎重に使用してください。あなたは質問を編集し、これをどのように使用するかのサンプルコードを追加してください。私は次に問題を指摘して指摘します。しかし、あなたの使用コードがなければ、それを伝えるのは難しいです。 – CodingYoshi

答えて

1

スレッドセーフではありません。あなたはこのような何かを試してみてください :GetData内のスレッドはそれを

  • 複数のスレッドを使用しようとしている間にAddDataからnextFreeを変更する別のスレッドを停止することは何もない理由

    • static class CircularArrayBuffer 
      { 
      
          static float[,] buffer; 
          static int columns, rows; 
          static int nextFree = 0; 
          static readonly ReaderWriterLockSlim rwLockSlim = new ReaderWriterLockSlim(); 
      
          public static void CreateBuffer(int _columns, int _rows) 
          { 
           columns = _columns; 
           rows = _rows; 
      
           buffer = new float[rows, columns]; 
           nextFree = 0;  //reset pointer to first free buffer 
          } 
      
          public static float[] GetData(int index) 
          { 
           try 
           { 
            rwLockSlim.EnterReadLock(); 
            if (index > rows) 
            { 
             throw new System.ArgumentException("Index cannot be more than rows", "index"); 
            } 
      
            float[] rowArray = new float[columns]; 
      
            Buffer.BlockCopy(buffer, (((nextFree - 1 + index) % rows) * 4 * columns), rowArray, 0, columns * 4); //takes 2 microseconds! 
           } 
           catch(Exception ex) 
           { 
            //handle the exception nicely 
           } 
           finally 
           { 
            rwLockSlim.ExitReadLock(); 
           } 
           return rowArray; 
          } 
      
          public static void AddData(float[] rowArray) //number of columns must be set! 
          { 
           try 
           { 
            rwLockSlim.EnterWriteLock(); 
            if (rowArray.Count() > columns) 
            { 
             throw new System.ArgumentException("Data length cannot be more than number of columns", "columns"); 
            } 
      
            Buffer.BlockCopy(rowArray, 0, buffer, nextFree * 4 * columns, columns * 4); 
            nextFree = (nextFree + 1) % rows; 
           } 
           catch(Exception ex) 
           { 
            //handle the exception nicely 
           } 
           finally 
           { 
            rwLockSlim.ExitWriteLock(); 
           } 
          } 
      } 
      

      そして、ここですAddDataにアクセスしてnextFreeを変更すると、Buffer.BlockCopyはデータを間違ったインデックスに入れます

  • +0

    したがって、writeメソッドがロックを取得した場合、読み込みを試みると読み込みはブロックされますか?私はそれがあなたが望むものだと思います。どうもありがとうございました。 – Tom

    +1

    'try ... finally'ブロックでロックを取得/解放する必要があります。例外があります。それらのロックを解放することは決してありません。これは間違っています。 – Andrey

    1

    GetData()の途中で書き込みが行われると、常に値が一致しなくなる可能性があります。おそらくロックを使ってGetdataとAdddataオペレーションをアトミックにして、一貫した値を取得したいと思うでしょう。また、サイドノートではおそらく今のところうまくいきますが、その価値が言及されて以来、すぐにロックを取得できない場合にUIスレッドをフリーズすることを避けるためにGet呼び出しを非同期にするのは常に良いことです。

    関連する問題