最終更新日時:
が更新

履歴 編集

function
<thread>

std::thread::コンストラクタ(C++11)

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_hintstack_size_hintなど)も渡せるようになった。args...の先頭に連続するスレッド属性型の引数がスレッドの名前やスタックサイズなどの設定として使われ、最初に現れた非属性型の引数が呼び出す関数オブジェクト、それ以降がその関数オブジェクトへ渡す実引数として扱われる。同じ属性型を複数回渡した場合、プログラムは不適格となる

      std::thread t{std::thread::name_hint("Worker"), f, 42};
      

  • (3) : コピーコンストラクタ。コピー不可。

  • (4) : ムーブコンストラクタ。スレッドの所有権を移動する。

要件

  • (2) : INVOKE(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)が有効な式でなければならない。
    • C++20まで : これに加えて、型FおよびArgsに含まれるすべての型Tiがムーブコンストラクト可能な型でなければならなかった。C++23では、is_constructible要件が既に目的を満たすため、この要件は削除された。

効果

  • (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のコピーの呼び出し開始」よりも前に発生する

事後条件

例外

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

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

備考

基本的な使い方

#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で宣言のみ行う手法で代用されている。

関連項目

参照