std::jthread::jthread

出自cppreference.com
 
 
並發支持庫
線程
(C++11)
(C++20)
this_thread 命名空間
(C++11)
(C++11)
(C++11)
協作式取消
互斥
(C++11)
通用鎖管理
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
條件變量
(C++11)
信號量
閂與屏障
(C++20)
(C++20)
未來體
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
風險指針
原子類型
(C++11)
(C++20)
原子類型的初始化
(C++11)(C++20 棄用)
(C++11)(C++20 棄用)
內存定序
(C++11)(C++26 棄用)
原子操作的自由函數
原子標誌的自由函數
 
 
jthread() noexcept;
(1) (C++20 起)
jthread( jthread&& other ) noexcept;
(2) (C++20 起)
template< class F, class... Args > 
explicit jthread( F&& f, Args&&... args );
(3) (C++20 起)
jthread( const jthread& ) = delete;
(4) (C++20 起)

構造新的 std::jthread 對象。

1) 構造不表示線程的新 std::jthread 對象。
2) 移動構造函數。構造的 std::jthread 對象表示之前由 other 表示的執行線程。此調用後 other 不再表示執行線程。
3) 創建與執行線程關聯的新 std::jthread 對象。新的執行線程開始執行:
std::invoke(decay-copy(std::forward<F>(f)), get_stop_token(),
            decay-copy(std::forward<Args>(args))...)
(C++23 前)

std::invoke(auto(std::forward<F>(f)), get_stop_token(),
auto(std::forward<Args>(args))...)

(C++23 起)

如果以上表達式非良構,那麼就會開始執行:

std::invoke(decay-copy(std::forward<F>(f)),
            decay-copy(std::forward<Args>(args))...)
.
(C++23 前)

std::invoke(auto(std::forward<F>(f)),
auto(std::forward<Args>(args))...)
.

(C++23 起)
decay-copy 的調用會在當前線程求值(C++23 前)auto 產生的值會在當前線程實質化(C++23 起),所以實參的求值和複製/移動中拋出的任何異常都會在當前線程拋出,而不會開始新線程。
這些重載只有在 std::remove_cvref_t<F>std::jthread 不是同一類型時才會參與重載決議。
如果以下任意值是 false,那麼程序非良構:
  • std::is_constructible_v<std::decay_t<F>, F>
  • (std::is_constructible_v<std::decay_t<Args>, Args> && ...)
  • std::is_invocable_v<std::decay_t<F>, std::decay_t<Args>...> ||
    std::is_invocable_v<std::decay_t<F>, std::stop_token, std::decay_t<Args>...>
構造函數的調用完成同步於新的執行線程上 f 副本的調用開始。
4) 複製構造函數被棄置;線程不可複製。兩個 std::jthread 對象不能表示同一執行線程。

參數

other - 用來構造此 std::jthread 對象的另一 std::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::refstd::cref)。

忽略來自函數的任何返回值。如果函數拋出異常,那麼就會調用 std::terminate。需要將返回值或異常傳遞迴調用方線程時可以使用 std::promisestd::async

示例

#include <chrono>
#include <iostream>
#include <thread>
#include <utility>

using namespace std::literals;

void f1(int n)
{
    for (int i = 0; i < 5; ++i)
    {
        std::cout << "正在执行线程 1\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}
 
void f2(int& n)
{
    for (int i = 0; i < 5; ++i)
    {
        std::cout << "正在执行线程 2\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}
 
class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i)
        {
            std::cout << "正在执行线程 3\n";
            ++n;
            std::this_thread::sleep_for(10ms);
        }
    }
    int n = 0;
};

class baz
{
public:
    void operator()()
    {
        for (int i = 0; i < 5; ++i)
        {
            std::cout << "正在执行线程 4\n";
            ++n;
            std::this_thread::sleep_for(10ms);
        }
    }
    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 << "n 的最终值是 " << n << '\n';
    std::cout << "f.n (foo::n) 的最终值是 " << f.n << '\n';
    std::cout << "b.n (baz::n) 的最终值是 " << b.n << '\n';
    // t4 在析构时合并
}

可能的輸出:

正在执行线程 2
正在执行线程 1
正在执行线程 4
正在执行线程 3
正在执行线程 3
正在执行线程 4
正在执行线程 2
正在执行线程 1
正在执行线程 3
正在执行线程 1
正在执行线程 4
正在执行线程 2
正在执行线程 3
正在执行线程 1
正在执行线程 4
正在执行线程 2
正在执行线程 3
正在执行线程 1
正在执行线程 4
正在执行线程 2
n 的最终值是 5
f.n (foo::n) 的最终值是 5
b.n (baz::n) 的最终值是 0

缺陷報告

下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。

缺陷報告 應用於 出版時的行為 正確行為
LWG 3476 C++20 重載 (3) 直接要求 F 和實參類型(在退化後)必須可移動構造 移除這些要求[1]
  1. std::is_constructible_v 已間接要求了可移動構造性。

參閱

構造新的 thread 對象
(std::thread 的公開成員函數) [編輯]
thrd_create 的 C 文檔