thread() noexcept; // (1)
template <class F, class ...Args>
explicit thread(F&& f, Args&&... args); // (2)
thread(const thread&) = delete; // (3)
thread(thread&&) noexcept; // (4)
概要
- (1) : デフォルトコンストラクタ。新しいスレッドを生成せず、空の状態にする。
- (2) : 新しいスレッドを生成し、そのスレッド上で引数
args...
を渡して、関数オブジェクトf
を呼び出す。 - (3) : コピーコンストラクタ。コピー不可。
- (4) : ムーブコンストラクタ。スレッドの所有権を移動する。
要件
- (2) : 型
F
およびArgs
に含まれるすべての型Ti
はムーブコンストラクト可能な型でなければならない。また、INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)
が有効な式でなければならない。
効果
-
(2) : 新しいスレッドを生成し、
INVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)
を実行する。ただしDECAY_COPY
は同コンストラクタを呼び出したスレッド上にて評価される。またf
のコピーの戻り値は無視される。-
DECAY_COPY(x)
はtemplate <class T> typename std::decay<T>::type decay_copy(T&& v) { return std::forward<T>(v); }
と定義される。おおよそ、x
が配列型なら先頭要素へのポインタ、x
が関数型ならその関数ポインタ、x
がコピーコンストラクト可能な型ならx
からコピーされたオブジェクト、x
がムーブコンストラクト可能な型ならx
からムーブされたオブジェクトとなる。 -
INVOKE(f, arg...)
はf
が関数オブジェクトならばf(arg...)
形式の関数呼び出しとなる。詳細はINVOKEの定義参照。 もしINVOKE(DECAY_COPY(std::forward<F>(f)), DECAY_COPY(std::forward<Args>(args))...)
呼び出しからcatchされない例外が送出された場合、std::terminate()
が呼び出されてプログラムは異常終了する。
-
同期操作
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始に対して同期する。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド
T1
上でのf
のコピーの呼び出し開始」よりも前に発生する。
事後条件
- (1) :
get_id() == id()
。 - (2) :
get_id() != id()
。*this
は新しいスレッドと関連付けられる。 - (4) : ムーブ前の
x.get_id() == get_id()
かつ ムーブ後のx.get_id() == id()
例外
-
(2) : 新しいスレッドの作成に失敗した場合、
system_error
例外を投げる。その例外オブジェクトには、以下のエラー状態が設定されうる:resource_unavailable_try_again
: 新たなスレッドを作るためのリソースが不足している。もしくはシステムやプロセスが規定するスレッド数の上限を超過した。
備考
- (2) :
- C++14 :
std::remove_cvref<F>::type
がstd::thread
型である場合、この関数はオーバーロード解決に参加しない。
- C++14 :
例
#include <memory>
#include <thread>
#include <utility>
#include <cassert>
int func(int v, int& ri, std::shared_ptr<int> sp, std::unique_ptr<int> up)
{
// spはコピーされた値が、upはムーブされた値が渡されてくる
v = ri = 42;
int x = *sp + *up;
assert(x == 7);
return x; // この戻り値は無視される
}
int main()
{
int i1 = 0;
int i2;
std::shared_ptr<int> sp0 = std::make_shared<int>(5);
std::unique_ptr<int> up0(new int(2));
std::thread t( func, i1, std::ref(i2), sp0, std::move(up0) );
// ...
t.join();
assert(i1 == 0 && i2 == 42);
return 0;
}
出力
バージョン
言語
- C++11
処理系
- Clang:
- GCC: 4.6.3 ✅, 4.7.0 ✅
- ICC:
- Visual C++: 2012 ✅, 2013 ✅, 2015 ✅
- 2012, 2013は、(2)での実引数の受け渡しにムーブを使用しない問題がある。上記の例でも、
std::unique_ptr<int>
の実引数でコンパイルエラーになる。 - 2012はコピーコンストラクタのdeleteに対応していないため、代わりにprivateで宣言のみ行う手法で代用されている。
- 2012, 2013は、(2)での実引数の受け渡しにムーブを使用しない問題がある。上記の例でも、