thread() noexcept; // (1) C++11
template <class F, class ...Args>
explicit thread(F&& f, Args&&... args); // (2) C++11
template <class ...Args>
explicit thread(Args&&... args); // (2) C++29
thread(const thread&) = delete; // (3) C++11
thread(thread&&) noexcept; // (4) C++11
概要
- (1) : デフォルトコンストラクタ。新しいスレッドを生成せず、空の状態にする。
-
(2) : 新しいスレッドを生成し、そのスレッド上で関数オブジェクトを呼び出す
- C++11 : 第1引数
fが呼び出す関数オブジェクトであり、残りの引数args...がfへ渡す実引数となる -
C++29 : シグニチャがすべての引数を1つのパック
args...で受け取る形へ変更され、関数オブジェクトより前に0個以上のスレッド属性(name_hint・stack_size_hintなど)も渡せるようになった。args...の先頭に連続するスレッド属性型の引数がスレッドの名前やスタックサイズなどの設定として使われ、最初に現れた非属性型の引数が呼び出す関数オブジェクト、それ以降がその関数オブジェクトへ渡す実引数として扱われる。同じ属性型を複数回渡した場合、プログラムは不適格となるstd::thread t{std::thread::name_hint("Worker"), f, 42};
- C++11 : 第1引数
-
(3) : コピーコンストラクタ。コピー不可。
- (4) : ムーブコンストラクタ。スレッドの所有権を移動する。
要件
- (2) :
INVOKE(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)が有効な式でなければならない。- C++20まで : これに加えて、型
FおよびArgsに含まれるすべての型Tiがムーブコンストラクト可能な型でなければならなかった。C++23では、is_constructible要件が既に目的を満たすため、この要件は削除された。
- C++20まで : これに加えて、型
効果
-
(2) : 新しいスレッドを生成し、
INVOKE(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)を実行する。ただしautoによって生成される値は、同コンストラクタを呼び出したスレッド上で実体化される。またfのコピーの戻り値は無視される。-
auto(x)は、xをコピーしたprvalueを生成する。おおよそ、xが配列型なら先頭要素へのポインタ、xが関数型ならその関数ポインタ、xがコピーコンストラクト可能な型ならxからコピーされたオブジェクト、xがムーブコンストラクト可能な型ならxからムーブされたオブジェクトとなる。 -
INVOKE(f, arg...)はfが関数オブジェクトならばf(arg...)形式の関数呼び出しとなる。詳細はINVOKEの定義参照。 もしINVOKE(auto(std::forward<F>(f)), auto(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++29)
#include <thread>
#include <iostream>
#include <pthread.h> // POSIX環境
void work(int n)
{
// ...
}
int main()
{
// スレッド名とスタックサイズのヒントを指定してスレッドを生成する。
// スレッド名はデバッガのスレッド一覧などに表示される
std::thread t{
std::thread::name_hint("Worker"),
std::thread::stack_size_hint(512 * 1024),
work,
42
};
// 標準ライブラリにスレッド名を取得するAPIはないが、
// ネイティブハンドルを通じてプラットフォームのAPIで取得できる
char name[16]{};
pthread_getname_np(t.native_handle(), name, sizeof(name));
std::cout << name << std::endl;
t.join();
}
出力例
Worker
バージョン
言語
- C++11
処理系
- Clang:
- GCC: 4.6.3 ✅, 4.7.0 ✅
- Visual C++: 2012 ✅, 2013 ✅, 2015 ✅
- 2012, 2013は、(2)での実引数の受け渡しにムーブを使用しない問題がある。上記の例でも、
std::unique_ptr<int>の実引数でコンパイルエラーになる。 - 2012はコピーコンストラクタのdeleteに対応していないため、代わりにprivateで宣言のみ行う手法で代用されている。
- 2012, 2013は、(2)での実引数の受け渡しにムーブを使用しない問題がある。上記の例でも、
関連項目
参照
- LWG Issue 929. Thread constructor
- C++11で、関数オブジェクトのみをとるコンストラクタと引数付きのコンストラクタが(2)の可変引数コンストラクタひとつに統合され、
explicitが付加された。また、実引数をDECAY_COPYによって呼び出し元スレッド上でコピーすることが規定された
- C++11で、関数オブジェクトのみをとるコンストラクタと引数付きのコンストラクタが(2)の可変引数コンストラクタひとつに統合され、
- LWG Issue 2097.
packaged_taskconstructors should be constrained - LWG Issue 3039. Unnecessary
decayinthreadandpackaged_task - LWG Issue 3476.
threadandjthreadconstructors require that the parameters be move-constructible- C++23で、
is_constructible要件が既に目的を満たすため、冗長だったムーブ構築可能(is_move_constructible)の要件が削除された
- C++23で、
- P0849R8
auto(x): decay-copy in the language- C++23で、実引数のコピーを表す規定が、説明専用の
DECAY_COPYから言語機能のauto(x)へ置き換えられた。規定の書き換えであり、動作は変わらない
- C++23で、実引数のコピーを表す規定が、説明専用の
- P2019R9 Thread attributes
- C++29で、スレッド属性を先頭引数として渡せるようになった