このページはC++11に採用された言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
概要
変数宣言の際に、記憶域としてthread_local
キーワードを指定することで、スレッドごとの静的記憶域に変数が保持される。
static
キーワードを記憶域として使用した変数は、プログラムを通してひとつの状態を持ち、プログラム終了時に変数が破棄される。thread_local
キーワードの場合はスレッドごとに状態を持ち、スレッド終了時に変数が破棄される。
// スレッドごとに、0から始まるIDを生成して返す関数
int create_id()
{
thread_local int current_id = 0;
return current_id++;
}
// 2つのスレッドそれぞれで、IDが0から始まる
std::thread t1([]{
int id1 = create_id(); // id1 == 0
int id2 = create_id(); // id2 == 1
});
std::thread t2([]{
int id1 = create_id(); // id1 == 0
int id2 = create_id(); // id2 == 1
});
t1.join();
t2.join();
仕様
thread_local
キーワードを記憶域として指定された変数は、「スレッド記憶域の有効期間 (thread storage duration)」を持つ。この記憶域を持つ変数は、スレッドの開始から終了までの有効期間を持つ。thread_local
キーワードは、static
とextern
を除き、register
といった他の記憶域キーワードと同時には使用できない。- スレッド終了時には、スレッド記憶域を持つ変数のデストラクタが呼び出される。
- スレッド記憶域を持つ変数のデストラクタ、もしくは名前空間スコープを持つスレッド記憶域変数のコンストラクタで例外が送出された場合、スレッドを初期化する関数の関数tryブロックでは、その例外を捕捉できない。
- プログラム終了時の動作は、
std::exit()
関数とstd::quick_exit()
関数のページを参照。
例
#include <iostream>
#include <thread>
#include <random>
// 範囲[min_inclusive, max_inclusive]でランダム一様分布する整数を生成する。
// スレッドごとに乱数の状態を持つ。
int random_range(int min_inclusive, int max_inclusive)
{
std::random_device seed_gen;
thread_local std::mt19937 engine(seed_gen());
std::uniform_int_distribution<int> dist(min_inclusive, max_inclusive);
return dist(engine);
}
int main()
{
// 複数のスレッドから並行にrandom_range()関数を呼び出せる
std::thread t1([]{
int random_value = random_range(0, 100);
// ※coutに対する一度の書き込みはスレッドセーフであるため、3つの書き込みを1つに統合。
std::cout << "thread1 : " + std::to_string(random_value) + "\n";
});
std::thread t2([]{
int random_value = random_range(0, 100);
std::cout << "thread2 : " + std::to_string(random_value) + "\n";
});
t1.join();
t2.join();
}
出力例
thread1 : 67
thread2 : 4
この機能が必要になった背景・経緯
マルチスレッドアプリケーションでは、スレッドごとにデータを一意に維持することがたびたび必要となる。これはスレッドローカルストレージと呼ばれ、多くのベンダーがスレッド記憶域の言語拡張を用意していた:
ベンダー | 機能 |
---|---|
GNU | Thread-Local Storage |
HP | スレッドローカルストレージを指定する記憶クラス指定子が存在した。 例: __declspec(__thread) int x = 0; |
IBM | Thread-Local Storage in What's New in XL C/C++ V9.0 |
IBM | __thread ストレージ・クラス指定子 |
Intel | GCC互換の__thread キーワードが存在した。 |
Microsoft | __declspec thread |
Oracle(旧Sun Microsystems) | Thread-Local Storage |
各ベンダーのこれらの経験を標準C++に導入することとなった。
関連項目
参照
- N1874 Thread-Local Storage
- N1966 Thread-Local Storage
- N2147 Thread-Local Storage
- N2280 Thread-Local Storage
- N2545 Thread-Local Storage
- N2659 Thread-Local Storage
- Why does Apple clang disallow C++11
thread_local
when 'official' clang supports it - Stack Overflow- Apple実装のClang(Xcode 7以下に付属のもの)が
thread_local
機能をサポートしない理由
- Apple実装のClang(Xcode 7以下に付属のもの)が