C++20中线程类std::jthread的使用

C++20中的std::jthread类表示一个执行线程 。它与std::thread具有相同的常规行为,但std::jthread在析构(destruction)时会自动重新加入(rejoin),并且可以在某些情况下被取消/停止(cancelled/stopped)。

与std::thread不同,std::jthread在逻辑上持有一个std::stop_source类型的内部私有成员,该成员维护一个共享的停止状态(stop-state)。std::jthread构造函数接受一个以std::stop_token作为第一个参数的函数 ,该参数由std::jthread从其内部std::stop_source传入。这使得该构造函数能够检查在执行过程中是否已请求停止,如果已请求则返回。

std::jthread对象也可能处于不代表任何线程的状态(after default construction, move from, detach, or join),并且执行线程可能不与任何std::jthread 对象关联(after detach)。

任何两个std::jthread对象都不能代表同一个执行线程;std::jthread不可拷贝构造或拷贝赋值,但可移动构造和移动赋值。

如果std::jthead无法启动,则抛std::system_error异常。

std::jthread构造函数的参数按值移动或拷贝。如果需要将引用参数传递给线程函数,则必须对其进行包装(例如,使用std::ref或std::cref)

std::jthread的析构函数:如果当前线程有一个关联线程即joinable()为true,则会先调用request_stop(),然后再调用join()

(1).如果std::jthread之前被请求stop,则调用request_stop()无效。

(2).std::jthread对象在以下情况后没有关联线程:它是被默认构造的、它被移出(moved from)、已调用join()、已调用detach()。

(3).如果join()抛出异常,则std::terminate()可能被调用。

std::jthread中的函数:

joinable():如果std::jthread对象标识了一个活动的执行线程,则返回true ,否则返回false。已完成代码执行但尚未joined的线程仍被视为活动的执行线程,因此是jonable的

get_id():返回std::jthread::id的值(std::thread::id的类型别名),用于标识与*this关联的线程。如果没有关联的线程,则返回默认构造的std::jthread::id。

hardware_concurrency():静态函数,返回支持的并发线程数。该值仅供参考。如果该值定义不明确或无法计算,则返回0。

join():阻塞当前线程,直到*this标识的线程完成执行。*this本身不执行同步。多个线程同时对同一个std::jthread对象调用join()会造成数据争用,从而导致未定义的行为。

detach():将执行线程与std::jthread对象分离,允许继续独立执行。线程退出后,所有分配的资源都将被释放。调用detach后,*this不再拥有任何线程。

swap:交换两个std::jthread对象的底层句柄。

测试代码如下:

cpp 复制代码
int test_jthread_constructor()
{
    auto func1 = [](int val) {
        for (auto i = 0; i < 2; ++i) {
            std::cout << ++val << std::endl;
            std::this_thread::sleep_for(100ms);
        }
    };

    auto func2 = [](int& val) {
        val = 88;
    };

    std::jthread jth1(func1, 5);
    std::jthread jth2{};
    std::cout << std::format("jth1 joinable: {}; jth2 joinable: {}", jth1.joinable(), jth2.joinable()) << std::endl;
    std::cout << "jth1 id: " << jth1.get_id() << "; jth2  id: " << jth2.get_id() << std::endl;

    jth2 = std::move(jth1);
    std::cout << std::format("jth1 joinable: {}; jth2 joinable: {}", jth1.joinable(), jth2.joinable()) << std::endl;
    std::cout << "jth1 id: " << jth1.get_id() << "; jth2  id: " << jth2.get_id() << std::endl;

    int val{ -1 };
    std::jthread jth3(func2, std::ref(val));
    jth3.join();
    std::cout << std::format("jth3 joinable: {}, val: {}", jth3.joinable(), val) << std::endl;
    std::cout << "jth3 id: " << jth3.get_id() << std::endl;

    std::cout << "concurrent threads are supported: " << std::jthread::hardware_concurrency() << std::endl;

    std::jthread jth4([] {
        std::cout << "jth4 running ..." << std::endl;
        std::this_thread::sleep_for(1s);
        std::cout << "jth4 end" << std::endl;
    });
    std::cout << "jth4 joinable: " << jth4.joinable() << ", id: " << jth4.get_id() << std::endl;

    jth4.detach();
    std::this_thread::sleep_for(3s);
    std::cout << "jth4 joinable: " << jth4.joinable() << ", id: " << jth4.get_id() << std::endl;

    jth4.swap(jth2);
    std::cout << std::format("jth2 joinable: {}; jth4 joinable: {}", jth2.joinable(), jth4.joinable()) << std::endl;

    std::swap(jth2, jth4);
    std::cout << std::format("jth2 joinable: {}; jth4 joinable: {}", jth2.joinable(), jth4.joinable()) << std::endl;

    return 0;
}

执行结果如下图所示:

get_stop_source():返回与std::jthread对象内部持有的相同共享停止状态相关联的std::stop_source。

get_stop_token():返回与std::jthread对象内部持有的相同共享停止状态相关联的std::stop_token。

request_stop():如果内部停止状态尚未收到停止请求,则向其发出停止请求。该判断以原子方式进行 ,如果已发出停止请求,则停止状态将以原子方式更新,以避免竞争条件(race conditions)。request_stop()只是向线程的std::stop_token发送"尽快退出"的信号,线程函数内要主动检查std::stop_token的stop_requested(),然后自行结束循环,不会结束线程,因此再调用joinable()还是true

cpp 复制代码
int test_jthread_request_stop()
{
    std::jthread jth([](std::stop_token token) {
        while (!token.stop_requested()) {
            std::cout << "running ...\n";
            std::this_thread::sleep_for(500ms);
        }
        std::cout << "stopped\n";
    });

    std::this_thread::sleep_for(3s);
    std::cout << "jth joinable: " << jth.joinable() << ", id: " << jth.get_id() << std::endl;
    jth.request_stop();
    std::this_thread::sleep_for(1s);
    std::cout << "jth joinable: " << jth.joinable() << ", id: " << jth.get_id() << std::endl;

	return 0;
}

执行结果如下图所示:

std::jthread和std::thread区别:

(1).std::jthread析构时会自动join(),无需手动调用join(),而std::thread析构前必选手动join()或detach()。

(2).std::jthread内置停止令牌(stop_token),可通过std::stop_token请求线程停止

(3).std::jthread兼容std::thread大多数接口。

(4).std::jthread比std::thread更安全。

GitHubhttps://github.com/fengbingchun/Messy_Test

相关推荐
charlie1145141915 小时前
精读C++20设计模式——行为型设计模式:解释器模式
c++·学习·设计模式·解释器模式·c++20
charlie1145141911 天前
精读 C++20 设计模式:行为型设计模式 — 状态机模式
c++·学习·设计模式·状态模式·c++20
奔跑吧邓邓子1 天前
【C++实战(57)】C++20新特性实战:解锁C++编程新姿势
c++·实战·c++20·c++20新特性
charlie1145141911 天前
精读 C++20 设计模式:行为型设计模式——观察者模式
c++·学习·观察者模式·设计模式·程序设计·c++20
charlie1145141911 天前
精读 C++20 设计模式:行为型设计模式 — 备忘录模式
c++·学习·设计模式·c++20·备忘录模式
charlie1145141911 天前
精读C++20设计模式——行为型设计模式:策略模式
c++·学习·设计模式·策略模式·c++20
charlie1145141912 天前
精读C++20设计模式——结构型设计模式:代理模式
c++·学习·设计模式·代理模式·c++20·概论
charlie1145141913 天前
精读C++20设计模式——创造型设计模式:单例模式
c++·学习·单例模式·设计模式·c++20
charlie1145141914 天前
精读《C++20设计模式》——创造型设计模式:原型模式
设计模式·程序设计·原型模式·c++20