std::jthread::jthread - cppreference.com
提供: cppreference.com
<tbody> </tbody>
|
|
(1) | (C++20以上) |
|
|
(2) | (C++20以上) |
|
|
(3) | (C++20以上) |
|
|
(4) | (C++20以上) |
新しい jthread オブジェクトを構築します。
1) スレッドを表さない新しい jthread オブジェクトを作成します。
2) ムーブコンストラクタ。 other が表していたスレッドを表す jthread オブジェクトを構築します。 この呼び出しの後 other はスレッドを表さなくなります。
3) 新しい std::jthread オブジェクトを作成し、それにスレッドを紐付けます。 新しいスレッドは、関数 f が第1引数として std::stop_token を受理する場合は
std::invoke(decay_copy(std::forward<Function>(f)), get_stop_token(), decay_copy(std::forward<Args>(args))...);
の実行を開始し、そうでなければ
std::invoke(decay_copy(std::forward<Function>(f)), decay_copy(std::forward<Args>(args))...);
の実行を開始します。
いずれの場合も、 decay_copy は以下のように定義されます。
template <class T> std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }
ただし decay_copy の呼び出しは、評価中および引数のコピー/ムーブ中に投げらるあらゆる例外が新しいスレッドを開始せず現在のスレッドで投げられるように、呼び出し元の文脈で評価されます。
コンストラクタの呼び出しの完了は新しいスレッドにおける f のコピーの呼び出しの開始に対して (std::memory_order の意味で) 同期します。
このコンストラクタは、 std::remove_cvref_t<Function> が std::jthread と同じ型である場合、オーバーロード解決に参加しません。
4) コピーコンストラクタは削除されています。 スレッドはコピー可能ではありません。 2つの std::jthread オブジェクトが同じスレッドを表すことはありません。
引数
| other | - | この jthread オブジェクトを構築するための別の jthread オブジェクト。
|
| f | - | 新しいスレッドで実行する Callable オブジェクト。 |
| args... | - | 新しい関数に渡す引数。 |
事後条件
1) get_id() が std::jthread::id() と等しい (すなわち joinable が false である) かつ get_stop_source().stop_possible() が false である。
2) other.get_id() が std::jthread::id() と等しいかつ get_id() が構築開始前の other.get_id() の値を返す。
3) get_id() が std::jthread::id() と等しくない (すなわち joinable が true である) かつ get_stop_source().stop_possible() が true である。
例外
3) スレッドを開始できなかった場合 std::system_error。 この例外はエラーコンディション std::errc::resource_unavailable_try_again またはその他の処理系固有のエラーコンディションを表すかもしれません。
ノート
スレッド関数への引数は値渡しでコピーまたはムーブされます。 スレッド関数に参照引数を渡す必要がある場合は (例えば std::ref や std::cref などで) ラップする必要があります。
関数からのあらゆる戻り値は無視されます。 関数が例外を投げた場合は std::terminate が呼ばれます。 戻り値や例外を呼び出し元スレッドに返すためには、 std::promise や std::async が使用できます。
例
#include <iostream> #include <utility> #include <thread> #include <chrono> void f1(int n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 1 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } void f2(int& n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } class foo { public: void bar() { for (int i = 0; i < 5; ++i) { std::cout << "Thread 3 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; class baz { public: void operator()() { for (int i = 0; i < 5; ++i) { std::cout << "Thread 4 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; int main() { int n = 0; foo f; baz b; std::jthread t0; // t0 はスレッドを表しません。 std::jthread t1(f1, n + 1); // 値で渡されます。 std::jthread t2a(f2, std::ref(n)); // 参照で渡されます。 std::jthread t2b(std::move(t2a)); // t2b が f2() の実行を引き継ぎます。 t2a はもはやスレッドを表しません。 std::jthread t3(&foo::bar, &f); // t3 はオブジェクト f 上で foo::bar() を実行します。 std::jthread t4(b); // t4 はオブジェクト b 上で baz::operator()() を実行します。 t1.join(); t2b.join(); t3.join(); std::cout << "Final value of n is " << n << '\n'; std::cout << "Final value of foo::n is " << f.n << '\n'; // t4 は破棄時に join されます。 }
出力例:
Thread 1 executing Thread 2 executing Thread 3 executing Thread 4 executing Thread 3 executing Thread 1 executing Thread 2 executing Thread 4 executing Thread 2 executing Thread 3 executing Thread 1 executing Thread 4 executing Thread 3 executing Thread 2 executing Thread 1 executing Thread 3 executing Thread 1 executing Thread 2 executing Final value of n is 5 Thread 4 executing Final value of foo::n is 5 Thread 4 executing