I've been writing ring buffers wrong all these years (2016)

2025/12/17 4:11

I've been writing ring buffers wrong all these years (2016)

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

要約

著者は、従来の実装よりもシンプルで効率的なリングバッファ設計―「2 つの 非マスク インデックスを自由に増加させ、基盤配列へアクセスする際だけマスクする」手法―が優れていると主張しますが、その採用はほとんど見られません。1 要素バッファで実験した結果、以下のことが判明しました。

  • 一般的な「配列 + 2 インデックス(読み取り・書き込み)」パターンは fullempty の状態が衝突し、スロットを 1 つ無駄にします。
  • 「配列 + インデックス + 長さ」を使う代替案は容量全体を利用できますが、リーダーとライタの両方が共有
    length
    フィールドを更新する必要があり、キャッシュ性能を低下させ、原子操作が必須になります。

自由に増加するインデックス手法はこれらの問題を回避します:無駄なスロットを排除し、ロジックを簡素化し、パフォーマンスを高めます。

uint32_t read, write;
static inline uint32_t mask(uint32_t v) { return v & (capacity-1); }

void push(v)   { assert(!full()); array[mask(write++)] = v; }
int  shift()   { assert(!empty()); return array[mask(read++)]; }
bool empty()   { return read == write; }
bool full()    { return size() == capacity; }
size_t size()  { return write - read; }

この手法の要件は次のとおりです。

  1. 言語が 符号なし整数のラップアラウンド をサポートしていること(さもなければインデックスは膨大な値に増加します)。
  2. capacity
    は 2 の冪であること。
  3. 実際に使用できる最大容量は、インデックスタイプの範囲の半分以下であること(例:32 ビット符号なしの場合 ≤ 2³¹–1)。

このテクニックは少なくとも 2004 年(Andrew Morton)から存在しますが、多くのコードは依然として古い「マスク」スタイルに従っています。これは歴史的慣性やオーバーフロー処理への懸念によるものと考えられます。著者は、なぜ劣ったバージョンが残存しているのか疑問を投げかけ、もし言語が符号なしラップアラウンドの意味論を受容すれば、将来の設計は自由に増加する方法へ切り替わる可能性があると示唆しています。採用すると容量無駄が減少し、キャッシュ挙動が改善され、同時実行リングバッファコードが簡素化されます―システムプログラマ、OS 開発者、および高性能循環バッファに依存するすべてのソフトウェアにとって有益です。

本文

そこで私は、1 要素のリングバッファを実装しようとしていました。
ご存知の通り、これは非常に合理的なデータ構造です。

書くのは思ったよりも面倒でした――その理由について後ほど触れます。考えてみると、ずっと「間違った」方法でリングバッファを書いていたことに気づきました。そしてもっと良いやり方があるという結論に至りました。


配列 + 2 つのインデックス

リングバッファを使ってキューを実装する一般的な方法は二通りあります。

  1. 配列をバックエンドとして使用し、配列へのポインタとして readwrite の 2 つのインデックスを保持します。
    ヘッドから値を取り出す ときは
    read
    を使って配列にアクセスし、その後
    read
    をインクリメントします。
    テールへ値を追加する ときは
    write
    を使って配列に書き込み、次に
    write
    をインクリメントします。

両方のインデックスは常に

0 … (capacity‑1)
の範囲に収まります。これはインデックスが増えた後でマスクして行います。

uint32 read;
uint32 write;

mask(val)  { return val & (array.capacity - 1); }
inc(index) { return mask(index + 1); }

push(val)  { assert(!full()); array[write] = val; write = inc(write); }
shift()    { assert(!empty()); ret = array[read]; read = inc(read); return ret; }

empty()    { return read == write; }
full()     { return inc(write) == read; }
size()     { return mask(write - read); }

欠点

この表現は配列の 1 要素を無駄にします
例えば配列が 4 要素なら、キューは最大で 3 要素しか保持できません。なぜかというと、空バッファでは

read == write
が成り立ちますが、満杯のバッファ(容量 N)でも同じ状態になってしまいます。そのため「満杯」を判定するには 1 スロットを未使用にしておく 必要があります。

大きなバッファでは無駄は目立ちませんが、1 要素しかない配列だと 100 % のオーバーヘッドになり、ペイロードゼロです!


配列 + インデックス + 長さ

もう一つの方法は インデックス長さ(length)を保持します。
要素を取り出すときは

read
を使い、
read
をインクリメントしながら
length
を減算します。追加するときは
mask(read + length)
に書き込み、
length
を増やします。

uint32 read;
uint32 length;

mask(val)  { return val & (array.capacity - 1); }
inc(index) { return mask(index + 1); }

push(val)  { assert(!full()); array[mask(read + length++)] = val; }
shift()    { assert(!empty()); --length; ret = array[read]; read = inc(read); return ret; }

empty()    { return length == 0; }
full()     { return length == array.capacity; }
size()     { return length; }

これなら全容量を使えますが、私はあまり好きではありません。
同時に読者と書き手がいる場合、両方のスレッドが

length
を更新するためキャッシュ効率が落ち、原子操作が必要になります。


配列 + 2 つの 未マスク インデックス

「両方の表現のメリットを得て、第三の状態変数を持たない方法」はあります――それは インクリメント時にマスクしない で、配列へアクセスするときだけマスクすることです。符号なし整数のオーバーフローが自然にゼロに戻るようにします。

uint32 read;
uint32 write;

mask(val)  { return val & (array.capacity - 1); }

push(val)  { assert(!full()); array[mask(write++)] = val; }
shift()    { assert(!empty()); return array[mask(read++)]; }

empty()    { return read == write; }
full()     { return size() == array.capacity; }
size()     { return write - read; }

無駄になっていたスロットが回収されます。インデックスの更新コードはシンプルで、状態判定も直感的です。

制限事項

  • 言語が符号なし整数のオーバーフローをラップアラウンドで扱うこと。
  • capacity
    は 2 のべき乗(モジュロ演算でも必要)。
  • 最大容量はインデックス型の範囲の半分まで(例:32 ビット符号なしなら (2^{31}-1))。

これらは通常問題になりません。


なぜ人々は「劣る」バージョンを使い続けているのでしょうか?

  • 慣習:教科書的手法が教えられ、再考せずに継承されます。
  • 安全性への懸念:符号なしオーバーフローはバグだと恐れる人もおり、意図しないオーバーフローを避けるため明示的にマスクします。
  • 非 2 のべき乗サイズ:容量が必ずしも 2 のべき乗でないケースでは、マスク版があればどんなサイズでも動作します。
  • 歴史的慣性:未マスク手法は(例:Andrew Morton, 2004)既に知られていましたが、多くの実装は古いパターンを続けています。

結論

容量が 2 のべき乗で、符号なし整数オーバーフローを利用できる場合は 未マスクインデックス を使う方が簡潔かつ効率的です。
「マスク後に増分」バージョンが残っているのは主に慣習とオーバーフローバグへの不安によるもので、必ずしも優れた設計だからではありません。

同じ日のほかのニュース

一覧に戻る →

2025/12/19 4:08

We pwned X, Vercel, Cursor, and Discord through a supply-chain attack

## Japanese Translation: Discordの新しいドキュメントプラットフォーム、Mintlifyにおいて、`/_mintlify/_static/[subdomain]/[…route]` エンドポイントを介して配信される任意の静的ファイルに悪意あるJavaScriptを注入できるクロスサイトスクリプティング(XSS)脆弱性が判明しました。16歳の高校生研究者は、Discord のドメインを指すSVG内にコードを埋め込み、そのリンクを開いた際にスクリプトが実行されることで、このサプライチェーン脆弱性を検証し、Mintlify の全顧客に影響する可能性があることを示しました。この欠陥は「xyzeva」という友人によって独立して確認され、両者は協力してテストと開示を行いました。報告後、Discord はドキュメントの公開を2時間停止し、以前のプラットフォームに戻し、すべての Mintlify ルートを削除(インシデントリンク: https://discordstatus.com/incidents/by04x5gnnng3)し、Mintlify は Slack を通じて問題を修正しました。研究者たちは合計で約11,000ドルの報奨金(Discordから4,000ドル、残りは Mintlify から)を受け取りました。この事例は、Twitter (X)、Vercel、Cursor、Discord 自体など多くのハイプロファイルユーザーに脅威を与える可能性がある単一のサードパーティコンポーネントのリスクを浮き彫りにし、外部サービスへのより厳格な検証と広範なセキュリティ監査の必要性を強調しています。

2025/12/17 6:04

Texas is suing all of the big TV makers for spying on what you watch

## Japanese Translation: > **概要:** > テキサス州司法長官ケン・パクストンは火曜日にソニー、サムスン、LG、ヒセン、TCL を対象に訴訟を提起し、同社のテレビが自動コンテンツ認識(ACR)を使用して視聴者の視聴内容を秘密裏に記録していると主張した。ACR はテレビ番組、ストリーミングサービス、YouTube、セキュリティカメラ、Apple AirPlay/Google Cast、および HDMI 接続デバイスなど、多岐にわたるソースから視聴覚データを取得し、訴訟ではメーカーがユーザーに対して隠れたまたは曖昧な開示で ACR の起動を促すと主張されている。サムスンとヒセンは 500 ミリ秒ごとにスクリーンショットを取得し、パクストンはデータがユーザーの知識なしに各社へ送信され、ターゲティング広告のために販売されると述べている。訴訟はテキサス州詐欺取引慣行法(Deceptive Trade Practices Act)を引用し、民事罰金およびテキサス州居住者からの ACR データ収集・共有・販売の停止を求めている。パクストンはまた TCL とヒセンの中国との関係に懸念を示し、同社のテレビを「中国支援監視デバイス」と呼んでいる。訴訟は Vizio が 2017 年に FTC およびニュージャージー州と合意した 220 万ドルの和解金を参照しており、類似の主張があったことを示している。サムスン、ソニー、LG、ヒセン、および TCL はまだコメント要請に応じていない。パクストンは「テレビを所有することは、ビッグテックや外国対立勢力に個人情報を渡すことを意味しない」と述べ、プライバシー保護への重点を強調した。

2025/12/19 3:55

How China built its ‘Manhattan Project’ to rival the West in AI chips

## Japanese Translation: **改善された要約** 深圳の研究所が、極紫外線(EUV)リソグラフィを使用して高度な半導体チップを製造できるプロトタイプを完成させました。EUVリソグラフィは、人間の髪の数千倍薄い回路をシリコンウェーハに刻むプロセスです。この機械は工場全床面積のほぼすべてを占める規模で、2025年初頭に完成し、現在テスト中です。元ASMLエンジニアがオランダ企業のEUV装置を逆解析して構築したもので、西側企業が長らく独占してきた技術です。プロトタイプが意図通りに機能すれば、中国はより細密な回路を持つチップを製造できるようになり、AIシステムやスマートフォン、高度兵器の性能向上につながります。この進展は、西側の独占的半導体製造能力から重要な技術が移転する可能性があり、世界のサプライチェーンと競争構造を変えることになるでしょう。

I've been writing ring buffers wrong all these years (2016) | そっか~ニュース