2

今日、boost::circularバッファのイテレータが、マルチスレッド環境で期待どおりに動作していないことを発見しました。(公平を期すために、シングルスレッドプログラムでも私が考えるよりも動作が異なります)。

特定のデータ シーケンスをループするために使用するイテレータを呼び出してbuffer.begin()表す場合。buffer.end()にさらにデータが追加されると、終了イテレータの値が変化しますcircular_bufferend()データが変更された後に別の呼び出しを行った場合、明らかに異なる結果が得られると予想されます。しかし、紛らわしいのは、既に変更した iterator オブジェクトの値です。

circle_buffer 内の設定された範囲のデータを操作できるイテレータを作成し、範囲の操作中に追加のデータがバッファに追加されても値が変更されないようにする方法はありますか?

そうでない場合、適用される可能性のある推奨される「非反復子」パターン、またはこれを許可する別のコンテナー クラスはありますか?

#include "stdafx.h"
#include <boost\thread.hpp>
#include <boost\thread\thread_time.hpp>
#include <boost\circular_buffer.hpp>

int _tmain(int argc, _TCHAR* argv[])
{
    boost::circular_buffer<int> buffer(20);

    buffer.push_back(99);
    buffer.push_back(99);
    buffer.push_back(99);

    boost::circular_buffer<int>::const_iterator itBegin = buffer.begin();
    boost::circular_buffer<int>::const_iterator itEnd = buffer.end();

    int count = itEnd - itBegin;
    printf("itEnd - itBegin == %i\n", count); //prints 3

    /* another thread (or this one) pushes an item*/
    buffer.push_back(99);

    /*we check values of begin and end again, they've changed, even though we have not done anything in this thread*/
    count = itEnd - itBegin;
    printf("itEnd - itBegin == %i\n", count); //prints 4 
}

ronag へのより詳細な応答の更新 プロデューサー コンシューマー タイプ モデルを探しています。ブースト ドキュメントに示されている制限付きバッファーの例は、必要なものに近いものです。ただし、次の 2 つの例外があります。

  1. バッファから一度に複数のデータ要素を読み取り、それらを検査できる必要がありますが、これは簡単ではないかもしれません。次に、バッファから削除するアイテムの数を選択します。

    偽の例: 文字列から hello と world という 2 つの単語を処理しようとしています。

    1 を読み取り、バッファに hel が含まれています。バッファから文字を削除しません。-more 読み取り 2 を生成、バッファには hellowo が含まれています。「hello」が 5 文字を削除していることがわかりました。バッファには wo が含まれています。さらに読み取り 3 を生成します。バッファには world が含まれています。

  2. バッファーがいっぱいでない限り、読み取り時にプロデューサー スレッドをブロックする必要はありません。

4

2 に答える 2

2

boost::circular_buffer::iterator docsによると、イテレータは有効なままにする必要があります。(コンテナーの変更と反復を同時に行うときに常に最初に確認することです。)したがって、サンプル コードは合法です。

何が起こっているかは、STL イテレータの規則によるものです:end()要素を指すのではなく、最後の 1 つ前の架空の要素を指します。4 番目の の後、(最初の要素) から(最後の要素の 1 つ前の要素) までpush_backの距離が増加しました。itBeginitEnd

1つの解決策は、具体的な要素を指すイテレータを保持することです。

itPenultimate = itEnd - 1;

からの距離は、範囲内にない限り、循環バッファーが拡張された場合でも同じままになりますitBeginitPenultimate

于 2011-11-23T21:03:36.627 に答える
1

ドキュメントは、循環バッファはスレッドセーフではなく、ユーザーがデータ構造をロックする責任があることを明示的に述べています。それはあなたの問題を解決するでしょう。

しかし、プロデューサー/コンシューマー スタイルのキューの方が問題に適しているかもしれません。

于 2011-11-23T20:54:33.683 に答える