g++における__threadキーワードとnon-POD型変数の初期化
g++における__threadキーワードとnon-POD型変数の初期化
#はじめに
GCCにはスレッド局所記憶のためのキーワードとして__threadがある。これはPOD(Plain Old Data)型のみ受け付け、non-POD型は対応していない。しかし、あるバージョンから対応したように見えるので覚書。
実行環境
- g++ 4.4.7
- g++ 4.8.5
- g++ 5.1.0
現象
以下のようなコードを書く。
#include <vector>
void func2(std::vector<int> &v);
int
func(int index){
static __thread std::vector<int> v;
func2(v);
return v[index];
}
これをg++ 4.4.7でコンパイルすると、non-POD型はthread-localにできない旨を怒られる。
$ g++ -c test.cpp
test.cpp: In function ‘int func(int)’:
test.cpp:7: error: ‘v’ cannot be thread-local because it has non-POD type ‘std::vector<int, std::allocator<int> >’
test.cpp:7: error: ‘v’ is thread-local and so cannot be dynamically initialized
要するに__thread指定できるのは、自明なコンストラクタを持つ場合のみに限られる・・・はずだった。
しかしこのコード、g++ 4.8.5や、5.1.0では問題なくコンパイルできる。
$ g++ -c test.cpp
$ # コンパイル成功
これに関連することを某ベンダーさんに問い合わせたら調べてくれて、どうやらGCC 4.8でC++11のthread_localキーワードに対応したのだが、このタイミングでnon-POD型に__threadを指定可能になったらしい。
こんなコードを書いてみる。
#include <vector>
void func2(std::vector<int> &v);
int
func(int index){
thread_local static std::vector<int> v;
func2(v);
return v[index];
}
さっきの__threadを、thread_localに書き換えただけのコード。thread_localキーワードはnon-POD型にも使えるので、これは問題なくコンパイルできる。
$ g++ -std=c++11 -c test2.cpp
$ # コンパイル成功
で、これもその方に教えてもらったのだが、g++ 4.8以降では、__thread指定したものと、thread_local指定したものが、全く同じコードを吐く(-Sで見てみるとわかる)。
まとめ
g++ 4.8以前ではnon-POD型な変数に__threadキーワードは指定できなかったが、g++ 4.8以降では指定できるようになった上に、thread_local指定した場合と全く同じコードを吐く。
ベンダーの人はそうとは明言しなかったが、おそらくthread_localが実装された段階で、__threadがthread_localのエイリアス扱いになったのではないか?それで、本来non-POD型は許されないはずの__threadキーワードにnon-POD型が許されるようになったのか?
ただし、GCC4.8 Changesには、
g++に
thread_localが実装されたが、これはGNUの__threadキーワードとは違うもので、ちょっと遅くなる場合があるからそういう時には__thread使ってね
みたいなことが書いてあって、どういうことになっているのかまだよくわかってない。
A Robot’s Sigh