std::jthread::jthread

来自cppreference.com
< cpp‎ | thread‎ | jthread
 
 
线程支持库
线程
(C++11)
(C++20)
(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++11)
(C++11)
条件变量
(C++11)
信号量
闩与屏障
(C++20)
(C++20)
future
(C++11)
(C++11)
(C++11)
(C++11)
 
 
jthread() noexcept;
(1) (C++20 起)
jthread( jthread&& other ) noexcept;
(2) (C++20 起)
template< class Function, class... Args >
explicit jthread( Function&& f, Args&&... args );
(3) (C++20 起)
jthread( const jthread& ) = delete;
(4) (C++20 起)

构造新 jthread 对象。

1) 构造不表示线程的新 jthread 对象。
2) 移动构造函数。构造的 jthread 对象表示之前由 other 表示的执行线程。此调用后 other 不再表示执行线程。
3) 创建与执行线程关联的新 jthread 对象。若函数 f 接受 std::stop_token 作为其首参数,则新执行线程开始执行
  • std::invoke(std::move(f_copy), get_stop_token(), std::move(args_copy)...) ,若该表达式合法;否则它开始执行
  • std::invoke(std::move(f_copy), std::move(args_copy)...)

任一情况下,

在调用方的环境执行这些对象的构造,故而在求值和移动/构造参数期间抛出的任何异常都在当前线程抛出,而不会开始新线程。若任何构造或 std::invoke 调用非法则程序非良构。
std::remove_cvref_t<Function>jthread 为相同类型则此构造函数不参与重载决议。
构造函数的完成同步于(按 std::memory_order 中定义) f 的副本在新线程上调用的开始。
4) 复制构造函数被删除;线程不可复制。没有二个 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::refstd::cref )。

忽略来自函数的任何返回值。若函数抛异常,则调用 std::terminate 。为将返回值或异常传回调用线程,可使用 std::promisestd::async

示例

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
using namespace std::literals;
 
void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 1 executing\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}
 
void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(10ms);
    }
}
 
class foo
{
public:
    void bar()
    {
        for (int i = 0; i < 5; ++i) {
            std::cout << "Thread 3 executing\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 << "Thread 4 executing\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 << "Final value of n is " << n << '\n';
    std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
    std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
    // t4 在析构时结合
}

可能的输出:

Thread 2 executing
Thread 1 executing
Thread 4 executing
Thread 3 executing
Thread 3 executing
Thread 4 executing
Thread 2 executing
Thread 1 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Thread 3 executing
Thread 1 executing
Thread 4 executing
Thread 2 executing
Final value of n is 5
Final value of f.n (foo::n) is 5
Final value of b.n (bar::n) is 0

参阅

构造新的 thread 对象
(std::thread 的公开成员函数)