2016-09-19 3 views
0

私はOctetクラスを持っています。これは8つのサンプルを "パッケージ化"して前方に送ります。新しいサンプルを追加し、すでに一杯かどうかを確認し、Octetの8つの値から構築されたFrameデータ構造を抽出する方法があります。プロパティがメソッド呼び出しの間で変更されているようですが、コードを変更する予定はありません

Octetクラスは、「まだ完全ではないため抽出できません」と「既に完全なためにサンプルを追加できません」という2種類の例外をスローします。そのためには、クライアントコードはAddを呼び出す前にいっぱいになっているかどうかをチェックして、すぐにフルに抽出し、リセットする必要があります。

問題は次のとおりです。クライアントクラス(Octetを使用している唯一のクライアントクラス)が、スローする操作の前に正しくチェックを実行しているように見えますが、エラー状態が発生しているにもかかわらず、ヒット。さらに悪いことに、デバッガがブレークしたときに値をチェックすると、正しい、つまり例外がスローされるべきではありません。

public class Client 
{ 
    private Octet _octet = new Octet(); 

    void ProcessNewSamples(IEnumerable<int> newSamples) 
    { 
     foreach (int sample in newSamples) 
     { 
      if (!_octet.IsFull) 
      { 
       _octet.Add(sample); 
      } 

      if (_octet.IsFull) 
      { 
       var frame = _octet.ExtractFrame(); 
       this.SendElsewhere(frame); 
       _octet.Reset(); 
      } 

     } 
    } 
} 


public class Octet 
{ 
    const int ARRAY_SIZE = 8; 
    int[] _samples = new int[ARRAY_SIZE]; 
    int _index = 0; 

    public bool IsFull { get { return _index >= 8; } } 

    public void Add(int sample) 
    { 
     if (IsFull) 
     { 
      throw new InvalidOperationException(); 
     } 
     else 
      _samples[_index++] = sample; 
    } 

    public Frame<int> ExtractFrame() 
    { 
     if (!IsFull) 
      throw new InvalidOperationException(); 
     else 
      return new Frame<int>(_samples); 

    } 

    public void Reset() 
    { 
     _samples = new int[ARRAY_SIZE]; 
     _index = 0; 
    } 
} 
+1

はProcessNewSamples'が複数から呼び出さ 'ですスレッド?その場合は、関数のオクテットへのアクセスをロックする必要があります。 – Nico

+0

@heinzbeinz [OK]を、私は、コードが実行されているタスクが誤って複数回呼び出されていることがわかりました。まあ、これはクライアントコードの不具合であると確信しており、修正するつもりです。しかし、「ロック」戦略に関しては、回答として投稿することはできますか?私はロックを入れるのに最適な場所がわからない。どうもありがとうございました! – heltonbiker

答えて

2

コメントに記載されているように、関数にアクセスする場合は、ロックを設定する必要があります。

SendElsewhereが速い場合、私は単に機能を中心にロックを配置します:

void ProcessNewSamples(IEnumerable<int> newSamples) 
{ 
    lock (this) 
    { 
     foreach (int sample in newSamples) 
     { 
      if (!_octet.IsFull) 
      { 
       _octet.Add(sample); 
      } 

      if (_octet.IsFull) 
      { 
       var frame = _octet.ExtractFrame(); 
       this.SendElsewhere(frame); 
       _octet.Reset(); 
      } 
     } 
    } 
} 

そうでなければ、私はすべてのフレームを集めるだろうし、その後それらを送信:

void ProcessNewSamples(IEnumerable<int> newSamples) 
{ 
    var frames = new List<Frame>(); 

    lock (this) 
    { 
     foreach (int sample in newSamples) 
     { 
      if (!_octet.IsFull) 
      { 
       _octet.Add(sample); 
      } 

      if (_octet.IsFull) 
      { 
       var frame = _octet.ExtractFrame(); 
       frames.Add(frame); 
       _octet.Reset(); 
      } 
     } 
    } 

    foreach (var frame in frames) 
    { 
     this.SendElsewhere(frame) 
    } 
} 
関連する問題