Rustのスレッドローカル変数について

Rustには2種類のスレッドローカル変数がある。

#[thread_local] 属性

#[thread_local] 属性は、指定した static アイテムをスレッドローカルにするようにLLVMに伝える。これによりC言語のスレッドローカル変数と同様に、ELFリンカ側の処理によりスレッドローカル変数が実現される。

この方法には以下のような問題点がある。

thread_local! マクロ

thread_local! マクロは、スレッドローカル変数に安全にアクセスするためのラッパーを生成する。例えば、

thread_local! {
    static X : Cell<u32> = Cell::new(0);
}

と書いたら、実際には以下のようなアイテムが生成される。

static X : LocalKey<Cell<u32>> = LocalKey { ... };

thread_local! は、もともとN:Mの並行性モデルを採用していたRustがグリーンスレッドを廃止して1:1に移行するにあたり、タスクローカル変数を提供するための local_data! を整理する形でできたものである。現在のネイティブスレッドの観点からも、このマクロ以下の点で優れているといえる。

  • 参照の有効期間が LocalKey::with により制限されるため、健全性の問題が解決されている。
  • ELFリンカに依存したスレッドローカル領域が提供されていない場合も、OS非依存の代替手段が利用される。

オブジェクトごとのスレッドローカル変数

以上とは別の話だが、オブジェクトごとにスレッドローカルなフィールドを持つ必要がある場合は thread_local crate というライブラリが使えるようだ。

まとめ

Rustでスレッドローカル変数を使うときは、 thread_local! マクロを使うのが望ましい。これは LocalKey という安全で移植性の高いラッパーを提供している。