网站域名怎么购买小程序开发网站
网站域名怎么购买,小程序开发网站,公明做网站多少钱,ftp上传网站全教程C进阶专栏#xff1a;http://t.csdnimg.cn/HGkeZ 目录
1.前言
2.std::is_invocable_v
3.std::jthread
3.1.构造函数
3.2.std::jthread无需join/detach使用实例
3.3.std::jthread处理外部请求中断实
3.4.处理中断请求示例代码
4.特性
5.总结 1.前言
C11以来提供了C原… C进阶专栏http://t.csdnimg.cn/HGkeZ 目录
1.前言
2.std::is_invocable_v
3.std::jthread
3.1.构造函数
3.2.std::jthread无需join/detach使用实例
3.3.std::jthread处理外部请求中断实
3.4.处理中断请求示例代码
4.特性
5.总结 1.前言
C11以来提供了C原生的多线程std::thread,这极大的方便了多线程的书写。在此之前书写多线程时需要平台原生API这对于跨平台尤其是跨多平台程序来讲多线程部分代码书写及维护都是极大的工作量。std::thread具有非常高的优势但是其也有自己的缺点以下代码为例
void using_thread_with_no_join()
{std::thread t{[](){std::coutsub thread xecate, thread idstd::this_thread::get_id();}};
}
运行如上代码时会出现崩溃堆栈信息如下 由如上堆栈信息可知崩溃原因为std::thread在析构时如果对象仍为joinable状态则会触发中断为避免崩溃需要在std::thread析构器前需要将其置于非joinable状态即需要主动调用join或detach接口。如果忘记了便会出现如上的崩溃。 C惯用法之RAII思想: 资源管理-CSDN博客 既然已经有了RAII思想了那必然是可以通过该思想来解决忘记join或detach导致崩溃的问题。所以std::jthread应运而生。当然std::jthread不止于此。
2.std::is_invocable_v std::is_invocable是C17 中引入的一个类型特性type trait用于在编译时检查给定的类型是否可以被调用。换句话说它可以用来检查一个类型比如函数、函数对象、lambda 表达式等是否可以作为函数调用操作符进行调用。 具体来说std::is_invocable模板接受一个函数类型和一组参数类型作为模板参数并提供一个名为value的静态成员常量用于表示给定的函数类型是否可以被调用。如果value为true则表示给定的函数类型可以被调用否则表示不可调用。 示例如下
#include type_traits struct Foo { void operator()(int, int) {}
}; int main() { // 检查函数是否可调用 static_assert(std::is_invocable_vdecltype(main), int, char); // 错误main不接受int和char作为参数 static_assert(std::is_invocable_vdecltype(main), void); // 正确main不接受任何参数 // 检查函数对象是否可调用 static_assert(std::is_invocable_vFoo, int, int); // 正确Foo有一个接受两个int参数的调用操作符 static_assert(!std::is_invocable_vFoo, double, double); // 错误Foo没有接受两个double参数的调用操作符 // 检查lambda是否可调用 auto lambda [](int a) { return a * 2; }; static_assert(std::is_invocable_vdecltype(lambda), int); // 正确lambda接受一个int参数
} 在上面的示例中std::is_invocable_v 是 std::is_invocable 的一个简化形式它直接返回 true 或 false而不是一个 std::true_type 或 std::false_type 的实例。 这个特性在模板元编程和泛型编程中特别有用因为它允许你在编译时基于可调用性来做出决策。
3.std::jthread
剖析其源码是了解其机理的最好方法std::jthread的部分源码整理如下
#if _HAS_CXX20
class jthread {
public:using id thread::id;using native_handle_type thread::native_handle_type;jthread() noexcept : _Impl{}, _Ssource{nostopstate} {}template class _Fn, class... _Args, enable_if_t!is_same_vremove_cvref_t_Fn, jthread, int 0_NODISCARD_CTOR explicit jthread(_Fn _Fx, _Args... _Ax) {if constexpr (is_invocable_vdecay_t_Fn, stop_token, decay_t_Args...) {_Impl._Start(_STD forward_Fn(_Fx), _Ssource.get_token(), _STD forward_Args(_Ax)...);} else {_Impl._Start(_STD forward_Fn(_Fx), _STD forward_Args(_Ax)...);}}~jthread() {_Try_cancel_and_join();}jthread(const jthread) delete;jthread(jthread) noexcept default;jthread operator(const jthread) delete;jthread operator(jthread _Other) noexcept {// note: the standard specifically disallows making self-move-assignment a no-op here// N4861 [thread.jthread.cons]/13// Effects: If joinable() is true, calls request_stop() and then join(). Assigns the state// of x to *this and sets x to a default constructed state._Try_cancel_and_join();_Impl _STD move(_Other._Impl);_Ssource _STD move(_Other._Ssource);return *this;}void swap(jthread _Other) noexcept {_Impl.swap(_Other._Impl);_Ssource.swap(_Other._Ssource);}_NODISCARD bool joinable() const noexcept {return _Impl.joinable();}void join() {_Impl.join();}void detach() {_Impl.detach();}_NODISCARD id get_id() const noexcept {return _Impl.get_id();}_NODISCARD stop_source get_stop_source() noexcept {return _Ssource;}_NODISCARD stop_token get_stop_token() const noexcept {return _Ssource.get_token();}bool request_stop() noexcept {return _Ssource.request_stop();}friend void swap(jthread _Lhs, jthread _Rhs) noexcept {_Lhs.swap(_Rhs);}_NODISCARD static unsigned int hardware_concurrency() noexcept {return thread::hardware_concurrency();}private:void _Try_cancel_and_join() noexcept {if (_Impl.joinable()) {_Ssource.request_stop();_Impl.join();}}thread _Impl;stop_source _Ssource;
};
#endif // _HAS_CXX20
由以上代码可知
1. 关注其构造函数jthread不存在拷贝构造函数和拷贝赋值存在移动构造函数和移动赋值运算符即jthread不可拷贝但是可以转移。
2. 关注其成员变量_Impl为std::thread类型即std::jthread采用RAII思想在构造函数内构造std::thread,但是在其析构函数内判断是否为joinable状态若其为joinable状态则调用std::thread的join函数致使std::thread在析构时恒为非joinable不会触发崩溃。关于此部分功能不再赘述完全为std::thread的套壳。
3. 关注其成员变量_Ssource为std::stop_source类型std::stop_source内维护stop_source的状态其状态为std::_Stop_state而std::_Stop_state实则是原子变量通过判断该原子变量的值来处理线程的外部请求中断。
3.1.构造函数
先看一下源码
template class _Fn, class... _Args, enable_if_t!is_same_vremove_cvref_t_Fn, jthread, int 0_NODISCARD_CTOR explicit jthread(_Fn _Fx, _Args... _Ax) {if constexpr (is_invocable_vdecay_t_Fn, stop_token, decay_t_Args...) {_Impl._Start(_STD forward_Fn(_Fx), _Ssource.get_token(), _STD forward_Args(_Ax)...);} else {_Impl._Start(_STD forward_Fn(_Fx), _STD forward_Args(_Ax)...);}}
...
从上面代码可以看出std::jthread的构造函数分为两种情况
1用std::is_invocable_v判断可调用对象_Fn的首个参数为std::stop_token通过_Ssource.get_token()获取自身的std::stop_token传入_Impl._Start函数中最终传入_Fn当中之前我一直没有看懂然后去看std::jthead的源码才恍然大悟。这种情况那么线程就可以这样定义
#include iostream
#include threadusing namespace std::literals::chrono_literals;void f(std::stop_token stop_token, int value)
{while (!stop_token.stop_requested()){std::cout value std::flush;std::this_thread::sleep_for(200ms);}std::cout std::endl;
}int main()
{std::jthread thread(f, 5); // 打印 5 6 7 8... 约 3 秒std::this_thread::sleep_for(3s);// jthread 的析构函数调用 request_stop() 和 join()。
}
上面的std::jthread构造传入的 f 满足std::is_invocable于是进入_Impl._Start(_STD forward_Fn(_Fx), _Ssource.get_token(), _STD forward_Args(_Ax)...); 开启线程。
2和上面相反的可调用对象( 普通函数、类成员函数、仿函数、lambda函数等等) 首个参数不是std::stop_token这种情况非常普通用的也比较多如下面示例
#includethreadvoid func(int i,std::jthread th){while (th.get_stop_token().stop_requested()) {std::this_thread::sleep_for(std::chrono::seconds(1));}
}void main() {std::jthread t1;t1 std::jthread(func, 12,std::ref(t1));// 终止线程的运行t1.request_stop();
} 线程函数func检查线程对象的令牌状态主线程通过改变线程对象的令牌状态来终止子线程的任务。 std::jthread的析构函数调用了join()所以这里我们不需要显示调用join()来等待。
3.2.std::jthread无需join/detach使用实例
std::jthread j{[]{std::cout sub jthread execuate, thread id std::this_thread::get_id();}};//正常输出并未崩溃某次执行结果如下//sub jthread execuate, thread id35732
3.3.std::jthread处理外部请求中断实
std::jthread提供三个接口并配合std::stop_token的stop_requested来实现外部请求中段处理。
//std::jthread
_NODISCARD stop_source get_stop_source() noexcept {return _Ssource;}_NODISCARD stop_token get_stop_token() const noexcept {return _Ssource.get_token();}bool request_stop() noexcept {return _Ssource.request_stop();}//stop token_NODISCARD bool stop_requested() const noexcept {const auto _Local _State;return _Local ! nullptr _Local-_Stop_requested();}
3.4.处理中断请求示例代码
void using_jthread_with_stop_token()
{std::jthread j{ [](std::stop_token token) {std::cout sub jthread execate, thread id std::this_thread::get_id()\n;for (int i 0; i 20; i){std::coutsub jthread i\n;std::this_thread::sleep_for(std::chrono::seconds(1));if (token.stop_requested()){std::coutexit sub jthread std::this_thread::get_id() \n;return;}}} };std::cout running main thread std::this_thread::get_id()\n;std::this_thread::sleep_for(std::chrono::seconds(5));j.request_stop();std::cout exit main thread std::this_thread::get_id() \n;
}//output result
/*
running main thread 34396
sub jthread execate, thread id21536
sub jthread 0
sub jthread 1
sub jthread 2
sub jthread 3
sub jthread 4
exit main thread 34396
exit sub jthread 21536
*/
由源码可知除直接使用std::jthread对象请求中断外还可以使用source即通过std::jthread的get_stop_source接口获得其source而后通过source来请求中断示例代码如下
void using_jthread_with_source_request_stop()
{std::jthread j{ [](std::stop_token token) {std::cout sub jthread execuate, thread id std::this_thread::get_id() \n;for (int i 0; i 20; i){std::cout sub jthread i \n;std::this_thread::sleep_for(std::chrono::seconds(1));if (token.stop_requested()){std::cout exit sub jthread std::this_thread::get_id() \n;return;}}} };auto source j.get_stop_source();std::thread t{[](std::stop_source source){std::cout running t thread std::this_thread::get_id() \n;std::this_thread::sleep_for(std::chrono::seconds(5));source.request_stop();},source};t.join();std::cout t thread joined \n;
}
//output result
/*
running t thread 20280
sub jthread execuate, thread id 4164
sub jthread 0
sub jthread 1
sub jthread 2
sub jthread 3
sub jthread 4
t thread joined
exit sub jthread 4164
*/
4.特性 std::jthread 是 C20 中引入的一个新特性它是 std::thread 的一个扩展专为与 C 的执行策略execution policies和并行算法parallel algorithms配合使用而设计。std::jthread 的主要目的是提供一种机制使得线程可以自动地与执行策略一起工作并在适当的时候进行调度和管理。 std::jthread 提供了以下特性 自动管理std::jthread 在其析构时会自动调用 std::jthread::join()从而避免了忘记调用 join() 或 detach() 而导致的资源泄露或程序行为不确定的问题。 异常传播如果 std::jthread 运行的函数抛出了异常并且这个异常没有被捕获那么 std::jthread 的析构函数会重新抛出这个异常。这使得在 std::jthread 对象的生命周期结束时能够更容易地诊断和处理异常。 执行策略集成std::jthread 可以与 C 的执行策略如 std::execution::par、std::execution::seq 等一起使用以控制并行算法的执行方式。这使得线程能够更容易地集成到并行计算框架中。 合作式取消std::jthread 支持一种称为“合作式取消”的机制允许在适当的时候请求线程停止执行。虽然这并不能强制线程立即停止但它提供了一种机制使得线程可以在检查取消请求时优雅地停止。
5.总结
1std::jthread析构自动汇合不回崩溃。 2std::jthread支持joinable、join、detach、get_id、hardware_concurrency等原生std::thread的接口故std::jthread可以无缝替换std::thread。 3std::jthread支持外部请求中断无需再向使用std::thread那样提供一个标志位来作为线程启停的标志。
参考
std::jthread - cppreference.com
std::thread - cppreference.com
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/92322.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!