0

Octet8 つのサンプルを「パッケージ化」してから送信するクラスがあります。新しいサンプルを追加し、すでにいっぱいかどうかをチェックFrameし、Octet.

このOctetクラスは、「まだいっぱいではないため抽出できません」と「すでにいっぱいであるためにサンプルを追加できません」という 2 種類の例外をスローします。そのために、クライアント コードは を呼び出す前に満杯かどうかを確認し、満杯にAddなったらすぐに抽出し、それをリセットする必要があります (正直なところ、非常に不十分なクラス コントラクトです)。

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

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;
    }
}
4

1 に答える 1

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)
    }
}
于 2016-09-19T20:03:12.020 に答える