vs2019 C++20 jthread
jthread
是有自动合并和取消支持的 std::thread
。jthread
包装了一下thread
,提供了线程运行中停止的接口。jthread
定义在<thread>
头文件中。
使用取消功能需要用到std::stop_token
。参考:<stop_token>
建议以后使用thread的都开始使用jthread,不必等到c++20出来。
- std::jthread对象销毁时,会调用join,等待其所表示的执行结束。
- 支持外部请求中止(通过get_stop_source、get_stop_token和request_stop)。
std::jthread为了实现上述新功能,带来了额外的性能开销(主要是多了一个成员变量)。而根据C++一直以来“不为不使用的功能付费”的设计哲学,他们自然就把这些新功能拆出来新做了一个类。1
01 jthread的一个实现
NICOLAI JOSUTTIS [尼古拉·乔苏蒂斯]2关于jthread的一个实现:
https://github.com/josuttis/jthread
这个实现没有使用C++20的新特性。只有jthread.hpp
和stop_token.hpp
两个文件,700多行代码。
https://github.com/josuttis/jthread/blob/master/source/jthread.hpp
https://github.com/josuttis/jthread/blob/master/source/stop_token.hpp
02 jthread用法
文中所有提到的代码,整理在:https://github.com/5455945/cpp_demo/tree/master/C%2B%2B20/jthread
02.01 cppreference上面的介绍
jthread在基本用法上面完全兼容thread。
https://zh.cppreference.com/w/cpp/thread/jthread/jthread
// https://zh.cppreference.com/w/cpp/thread/jthread/jthread
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include "jthread.hpp" // https://github.com/josuttis/jthread/tree/master/source
void f1(int n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 1 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void f2(int& n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 2 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
class foo
{
public:
void bar()
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 3 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
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(std::chrono::milliseconds(10));
}
}
int n = 0;
};
void test_jthread_cppreference01()
{
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 foo::n is " << f.n << '\n';
// t4 在析构时结合
}
02.02 可协作中断的用法
参考 C ++ 20中的新线程(jthread)功能
使用request_stop()
向jthread
线程发送停止线程请求;在jthread
线程中使用stop_requested()
来判断是否收到停止线程请求。如果收到停止请求,即做出退出线程反应。
void sleep(const int seconds) {
std::this_thread::sleep_for(std::chrono::seconds(seconds));
}
void test_jthread03() {
std::jthread jt{ [](std::stop_token st) {
while (!st.stop_requested()) { // 有停止线程请求的处理
std::cout << "Doing work\n";
sleep(1);
}
} };
sleep(5);
jt.request_stop(); // 请求线程停止,因有响应停止请求而终止线程
jt.join();
}
02.03 NICOLAI JOSUTTIS提供了大量测试用例
https://github.com/josuttis/jthread/tree/master/source中提供了大量测试用例,对理解jthread的用法很有帮助。