Skip to content

Latest commit

 

History

History
216 lines (171 loc) · 9.53 KB

File metadata and controls

216 lines (171 loc) · 9.53 KB

コンストラクタ

  • thread[meta header]
  • std[meta namespace]
  • jthread[meta class]
  • function[meta id-type]
  • cpp20[meta cpp]
jthread() noexcept;                      // (1) C++20

template <class F, class... Args>
explicit jthread(F&& f, Args&&... args); // (2) C++20

template <class... Args>
explicit jthread(Args&&... args);        // (2) C++29

jthread(const jthread&) = delete;        // (3) C++20

jthread(jthread&&) noexcept;             // (4) C++20

概要

  • (1) : デフォルトコンストラクタ。新しいスレッドを生成せず、空の状態にする。
  • (2) : 新しいスレッドを生成し、そのスレッド上で関数オブジェクトを呼び出す
    • C++20 : 第1引数fが呼び出す関数オブジェクトであり、残りの引数args...fへ渡す実引数となる

    • C++29 : シグニチャがすべての引数を1つのパックargs...で受け取る形へ変更され、関数オブジェクトより前に0個以上のスレッド属性(name_hintstack_size_hintなど)も渡せるようになった。args...の先頭に連続するスレッド属性型の引数がスレッドの名前やスタックサイズなどの設定として使われ、最初に現れた非属性型の引数が呼び出す関数オブジェクト、それ以降がその関数オブジェクトへ渡す実引数として扱われる。同じ属性型を複数回渡した場合、プログラムは不適格となる

      std::jthread t{std::jthread::name_hint("Worker"), f, 42};
  • (3) : コピーコンストラクタ。コピー不可。
  • (4) : ムーブコンストラクタ。スレッドの所有権を移動する。

テンプレートパラメータ制約

  • (2) :

適格要件

効果

  • (2) :
    • メンバ変数として保持しているstd::stop_source型オブジェクトを初期化する

    • 以下の式が有効であればそれで新たなスレッドを生成して実行し、

      invoke(auto(std::forward<F>(f)), get_stop_token(), auto(std::forward<Args>(args))...)
      • invoke[link /reference/functional/invoke.md]
      • get_stop_token()[link get_stop_token.md]
    • そうでなければ以下の式でスレッドを生成して実行する

      invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)
      • invoke[link /reference/functional/invoke.md]
    • この呼び出しでの戻り値は無視される。この関数呼び出しが例外を送出する場合、呼び出し元スレッドでstd::terminateが呼び出される

同期操作

  • (2) : 同コンストラクタの呼び出し完了は、fのコピーの呼び出し開始に対して同期する。つまり、「コンストラクタ呼び出し側スレッドT0でのコンストラクタ呼び出し完了」は、「新しいスレッドT1上でのfのコピーの呼び出し開始」よりも前に発生する

事後条件

例外

  • (2) : 新しいスレッドの作成に失敗した場合、system_error例外を投げる。その例外オブジェクトには、以下のエラー状態が設定されうる:

    • resource_unavailable_try_again : 新たなスレッドを作るためのリソースが不足している。もしくはシステムやプロセスが規定するスレッド数の上限を超過した。

基本的な使い方

#include <iostream>
#include <cstdint>
#include <thread>
#include <chrono>

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;
}
  • std::stop_token[link /reference/stop_token/stop_token.md]
  • stoken.stop_requested()[link /reference/stop_token/stop_token/stop_requested.md]
  • jt1.request_stop()[link request_stop.md]

出力例

48458670270
499999500000

スレッド属性を指定する (C++29)

#include <thread>
#include <iostream>
#include <pthread.h> // POSIX環境

void work(int n)
{
  // ...
}

int main()
{
  // スレッド名とスタックサイズのヒントを指定してスレッドを生成する。
  // スレッド名はデバッガのスレッド一覧などに表示される
  std::jthread t{
    std::jthread::name_hint("Worker"),
    std::jthread::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;
}
  • std::jthread::name_hint[link ../thread/name_hint.md]
  • std::jthread::stack_size_hint[link ../thread/stack_size_hint.md]
  • t.native_handle()[link native_handle.md]

出力例

Worker

バージョン

言語

  • C++20

処理系

関連項目

参照