従来の1ブロックの循環バッファの場合、これはアトミック操作では安全に実行できないと思います。1回の読み取りで多くのことを行う必要があります。次のような構造があるとします。
uint8_t* buf;
unsigned int size; // Actual max. buffer size
unsigned int length; // Actual stored data length (suppose in write prohibited from being > size)
unsigned int offset; // Start of current stored data
読んだら、次のことを行う必要があります(これはとにかく私がそれを実装した方法です、後で説明するようにいくつかのステップを交換することができます):
- 読み取り長が保存長を超えていないか確認してください
- オフセット+読み取り長がバッファー境界を超えていないかどうかを確認します
- データを読み上げる
- オフセットを増やし、長さを減らします
これを機能させるために、確実に同期(非常にアトミック)に何をすべきですか?実際にステップ1と4を1つのアトミックステップに結合するか、明確にするために:これを同期化してください:
- read_lengthを確認してください。これは次のようになります。
read_length=min(read_length,length);
- read_lengthで長さを減らします:
length-=read_length
- オフセットからローカルコピーを取得する
unsigned int local_offset = offset
- read_lengthでオフセットを増やします:
offset+=read_length
その後、local_offsetから始めてmemcpy(または何でも)を実行し、読み取りが循環バッファーサイズ(2つのmemcpyに分割)を超えているかどうかを確認します...。これは「かなり」スレッドセーフです。writeメソッドは、読み取っているメモリを上書きする可能性があるため、その可能性を最小限に抑えるために、バッファが本当に十分に大きいことを確認してください。
さて、3と4(リンクリストの場合はそうなると思います)または1と2を不可分操作で組み合わせることができると想像できますが、このすべての取引を1つの不可分操作で行うことはできません:)。
ただし、消費者が非常に賢く、何を読むべきかを常に知っている場合は、「長さ」のチェックをやめることができます。書き込みオフセットを決定するための(offset + length)%sizeの古い方法は機能しなくなるため、新しいwoffset変数も必要になります。これは、実際には常にリストから1つの要素(=固定、既知のサイズ)を読み取るリンクリストの場合に近いことに注意してください。また、ここで、循環リンクリストにすると、その時点で読んでいる位置に多くの読み取りまたは書き込みを行うことができます。
最後に、私のアドバイスは、ロックを使用することです。リアルタイム720p60ビデオストリーマーにはCircularBufferクラスを使用し、読み取りと書き込みに完全に安全です)。ロックによる速度の問題はまったくありません。