リングバッファ(ring buffer、circular buffer)は、限られたメモリのあるシステム、デバイスドライバ、ネットワーク、およびマルチタスクシステムで頻繁に使用されます。この概念は、OSの初期開発段階から、メモリを効率的に使用し、取り出し後の要素のシフトにリソースを浪費しないことが重要でした。
典型的な課題は、「バッファが満杯」の状態と「バッファが空」の状態の適切な処理、データの上書き防止の欠如、マルチスレッド環境における複雑な同期です。境界の混同やインデックスの誤ったチェックによってエラーが発生する可能性があります。
リングバッファオブジェクトは、配列、2つのインデックス(headとtail)、および必要に応じてカウンタ変数または「満杯」と「空」の状態を区別するための追加ロジックで実装されます。読み書きはバッファのサイズをモジュロで行います。
#define BUF_SIZE 8 char buffer[BUF_SIZE]; int head = 0, tail = 0; // head – 書き込み、tail – 読み込み // 書き込み if (((head + 1) % BUF_SIZE) != tail) { buffer[head] = data; head = (head + 1) % BUF_SIZE; } else { // バッファが満杯 } // 読み込み if (head != tail) { char d = buffer[tail]; tail = (tail + 1) % BUF_SIZE; }
キーとなる特性:
完全に満杯のバッファと完全に空のバッファを区別するにはどうすればよいですか?
head == tailで、空のバッファを最もよく識別します。満杯の場合は、1つのセルを空けておくか、サブカウンターに要素数を明示的に保持する必要があります。
ロックなしでマルチスレッド環境でバッファを使用できますか?
いいえ、標準的な場合、同時に読み書きが行われると、競争状態が発生する可能性があります。原子操作を使用するか、ロックを使用する必要があります。
headまたはtailのオーバーフローを制御しないとどうなりますか?
オーバーフローが発生すると、配列の境界を越え、未定義の動作を引き起こし、メモリが破損する可能性があります。
開発者はリングバッファを実装し、head == tailを同時に「空」と「満杯」と解釈しました。その結果、オーバーフロー信号が失われました。
利点:
欠点:
代わりに要素のカウンタ変数を追加するか、headがtailに完全に追いつかないように1つのスロットを予約しました。
利点:
欠点: