jthread() noexcept; // (1) C++20
template <class F, class... Args>
explicit jthread(F&& f, Args&&... args); // (2) C++20
jthread(const jthread&) = delete; // (3) C++20
jthread(jthread&&) noexcept; // (4) C++20
概要
- (1) : デフォルトコンストラクタ。新しいスレッドを生成せず、空の状態にする。
- (2) : 新しいスレッドを生成し、そのスレッド上で引数
args...を渡して、関数オブジェクトfを呼び出す。 - (3) : コピーコンストラクタ。コピー不可。
- (4) : ムーブコンストラクタ。スレッドの所有権を移動する。
テンプレートパラメータ制約
- (2) :
remove_cvref_t<F>がjthreadではないことdecay_t<F>およびdecay_t<Args>の各型がCpp17MoveConstructible要件を満たすこと
適格要件
- (2) : 以下の条件がすべて
trueであることis_constructible_v<decay_t<F>, F>(is_constructible_v<decay_t<Args>, Args> && ...)is_move_constructible_v<decay_t<F>>(is_move_constructible_v<decay_t<Args>> && ...)is_invocable_v<decay_t<F>, decay_t<Args>...> || is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>
効果
-
(2) :
- メンバ変数として保持している
std::stop_source型オブジェクトを初期化する -
以下の式が有効であればそれで新たなスレッドを生成して実行し、
invoke(decay-copy(std::forward<F>(f)), get_stop_token(), decay-copy(std::forward<Args>(args))...) -
そうでなければ以下の式でスレッドを生成して実行する
invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...) -
この呼び出しでの戻り値は無視される。この関数呼び出しが例外を送出する場合、呼び出し元スレッドで
std::terminateが呼び出される
- メンバ変数として保持している
同期操作
- (2) : コンストラクタ呼び出しの完了は、
fのコピーの呼び出し開始に対して同期する 新しいスレッドを生成し、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からムーブされたオブジェクトとなる。
同期操作
- (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始に対して同期する。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッド
T1上でのfのコピーの呼び出し開始」よりも前に発生する。
事後条件
- (1) :
get_id() == id()がtrueとなることget_stop_source()で取得されるstd::stop_sourceオブジェクトのstop_possible()がfalseであること
- (2) :
get_id() != id()がtrueとなることget_stop_source()で取得されるstd::stop_sourceオブジェクトのstop_possible()がtrueであること*thisは新しいスレッドと関連付けられること
- (4) :
x.get_id() == get_id()がtrueであることget_id()がムーブ前のx.get_id()の値であることx.get_stop_source().stop_possible()がfalseであること
例外
-
(2) : 新しいスレッドの作成に失敗した場合、
system_error例外を投げる。その例外オブジェクトには、以下のエラー状態が設定されうる:resource_unavailable_try_again: 新たなスレッドを作るためのリソースが不足している。もしくはシステムやプロセスが規定するスレッド数の上限を超過した。
例
#include <iostream>
#include <cstdint>
#include <thread>
std::uint64_t sum1 = 0;
std::uint64_t sum2 = 0;
void f1(std::stop_token stoken, std::uint64_t n)
{
sum1 = 0;
for (std::uint64_t i = 1; i < n; ++i) {
if (stoken.stop_requested()) {
// 中断リクエストがきたのでスレッドを終了する
break;
}
sum1 += i;
}
}
void f2(std::uint64_t n)
{
sum2 = 0;
for (std::uint64_t i = 1; i < n; ++i) {
sum2 += i;
}
}
int main()
{
{
// 関数の第1引数がstd::stop_token型である場合、
// スレッドに中断リクエストを送れるようになる
std::jthread jt1 {f1, 1'000'000};
std::this_thread::sleep_for(std::chrono::milliseconds{3});
jt1.request_stop(); // スレッドの中断要求を発行
// スレッド実行する関数がstd::stop_tokenを受け取らない場合、
// 中断リクエストを使用せず、
// デストラクタで自動的にjoinするスレッドオブジェクトとして使用する
std::jthread jt2 {
[] { f2(1'000'000); }
};
} // jthreadのデストラクタでは、中断要求を発行し、スレッドの終了を待機する
std::cout << sum1 << std::endl; // 計算できたところまで表示
std::cout << sum2 << std::endl;
}
出力例
48458670270
499999500000
バージョン
言語
- C++20
処理系
- Clang:
- GCC: 10.2.0 ✅
- Visual C++: ??