网易网站开发,php做网站自动生成前台吗,ps做网站设计,有没有网址一、多线程开发
c11以前#xff0c;是不包含线程库的#xff0c;开发多线程#xff0c;必须使用OS系统自带的线程API#xff0c;这就导致了很多问题#xff0c;最主要的是#xff0c;跨平台的开发#xff0c;一般要保持几个主流应用的库的代码支持#xff0c;特别是对…一、多线程开发
c11以前是不包含线程库的开发多线程必须使用OS系统自带的线程API这就导致了很多问题最主要的是跨平台的开发一般要保持几个主流应用的库的代码支持特别是对Win平台和Linux平台的两个线程库的支持否则就无法实现简单的跨平台的功能。而两个平台的多线程的使用差异和一些细节不同的比如事件Event在Linux上没有。而条件变量在Win平台上没有就更容易使一些应用场景的开发的复杂性大幅提高。 而到了c11以后提供了std::thread这个多线程的支持可以说大幅的降低了跨平台开发的复杂性。 但是在实际的应用过程中又遇到了一些新的需求变化比如应用的方便性和多线程运行过程中的可操作性及可见性上都需要提供新的接口。按照c设计者们的一贯作风他们不会在基础的std::thread本身进行修改那么他们就对这个类进行了再封装增加了上述的功能然后提出了std::jthread这个类。
二、jthread的功能和实现
一般来说接口越丰富那么这个类功能越强大但是反过来缺点就是不容易掌握并且容易忘记调用在使用std::thread时有没有忘记调用join()或者detach()的时候自动调用好不好线程函数运行过程中可不可以可以动态请求交互一下而不是靠各种变量来预先进行控制。对在std::jthread上都实现了。 看一看标准文档是如何定义的
std::jthread::jthread
jthread() noexcept; (1) (C20 起)
jthread( jthread other ) noexcept; (2) (C20 起)
template class Function, class... Args
explicit jthread( Function f, Args... args );(3) (C20 起)
jthread( const jthread ) delete; (4) (C20 起)
第一个表示创建新的jthread对象第二个表示移动语义既然移动了那么原来线程停止执行线程由新线程执行第三个表示线程函数f接受 std::stop_token 作为其首参数则新线程开始执行
std::invoke(decay_copy(std::forwardFunction(f)),get_stop_token(),decay_copy(std::forwardArgs(args))...);否则它开始执行
std::invoke(decay_copy(std::forwardFunction(f)),decay_copy(std::forwardArgs(args))...);任一情况下 decay_copy 定义为
template class T
std::decay_tT decay_copy(T v) { return std::forwardT(v); }除了在调用方的语境中执行 decay_copy 故而在求值和移动/构造参数期间抛出的任何异常都在当前线程抛出而不会开始新线程。 构造函数的完成同步于按 std::memory_order 中定义 f 的副本在新线程上调用的开始。 若 std::remove_cvref_t 与 std::jthread 为相同类型则此构造函数不参与重载决议。 最后一个表示不可复制也就是说只能它自己执行线程没有任何其它一个std::jthread对象可以表示同一线程。
std::jthread的成员函数里可以看支持查看硬件并发数的函数交换线程对象的函数协作请示的函数等更多的详情可以参看一下 https://zh.cppreference.com/w/cpp/thread/jthread/jthread https://zh.cppreference.com/w/cpp/header/stop_token
三、应用
线程的中断和取消是需要高度引起注意的一不小心强行KILL的线程中的各种资源或者句柄就没有回收导致各种泄露。这也是在多线程编程中普遍有一个要求就是让线程自己执行完毕退出而为了这个要求就需要牺牲一下控制的效率。 当然先从std::thread的多线程编程的例子看
#include Windows.h
#include iostream
#include thread
#include chronobool quit false;void SleepTime(int sec)
{std::this_thread::sleep_for(std::chrono::seconds(sec));
}
void ThreadWorker()
{//work work workstd::cout thread start,working! std::endl;
}void MainWorker()
{std::cout main thread start,working! std::endl;
}
int main()
{std::thread t std::thread([]() {while (!quit){ThreadWorker();SleepTime(2);}});//Sleep(3);MainWorker();t.join();//t.detach();
}
这个DEMO非常简单在主线程中启动了一个子线程需要注意一下注释的延时的情况主要是起一个先后交替的条件。主线程在执行完成自己的工作后就会join等待子线程的完成像上面这种情况就死循环了不会停止。如果需要停止只能使用设置quit为True或者强制的命令等不友好的手段了。首先看一下换成jthread会是啥样其它代码都没有改变只是修改了下面的代码
std::jthread t std::jthread([]() {while (!quit){ThreadWorker();SleepTime(2);}
});需要包含的jthread等的头文件可以去github或者相关的网站上下载这里只提供一处并对此表示感谢 https://github.com/josuttis/jthread/tree/master/source 上面的两处代码的运行结果是完全一样的没有什么不同。那用这个类的优势呢别急把main函数改一下
int main()
{std::jthread t std::jthread([]() {while (!quit){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();//t.join();//t.detach();
}
把最后一行注释再编译运行仍然没有啥问题有一点不同了吧。这可以避免粗心大意的同学出现意外错误吧。再看一下如果设置quit为true那么线程会怎么办没啥大问题到了判断就退出了可是如果有多个线程在执行是不是要设置多个类似的变量呢答案是肯定的。这时候儿看看jthread的协作中断
int main()
{std::jthread t std::jthread([]() {while (!quit){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();t.request_stop();//简单增加一行代码
}编译运行发现没啥反应好再修改一下线程函数
int main()
{std::jthread t std::jthread([](std::stop_token st) {while (/*!quit*/!st.stop_requested()){ThreadWorker();SleepTime(2);}});Sleep(3);MainWorker();//getchar();t.request_stop();//t.join();//t.detach();getchar();
}这个时候儿发现没啥问题了注意上面getchar()函数的位置如果在后面则执行一次就退出了。如果在前面就继续不断执行。把t.request_stop();这一行也注释发现程序仍然和不注释一样看来这个jthread里做了什么运作看一下它的析构函数
inline jthread::~jthread() {if (joinable()) { // if not joined/detached, signal stop and wait for end:request_stop();join();}
}明白了吧。至于为什么不用detach(),可能是大牛们觉得join()会更安全一些吧。毕竟等待完成后所有的对象都被回收了。下面再看官网提供的一个例子
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;
};
int main()
{foo f;std::jthread t3(foo::bar, f);std::jthread t std::jthread([](std::stop_token st) {while (/*!quit*/!st.stop_requested()){ThreadWorker();SleepTime(2);}});std::cout t.hardware_concurrency() std::endl;Sleep(3);MainWorker();getchar();t.request_stop();//t.join();//t.detach();
}执行一下就可以看出上面提到的decay_copy这个模板函数的使用没啥不容易理解的。
4、总结
其实还有几个特点值得说说但不准备再讲了虽然已经投票完成确定了c20的标准但毕竟还没有正式增加进去大家有兴趣可以看看源码。整体来看c应用还是越来越方便这对c来说肯定是个好事情。现在就希望VS2019或者GCC11中尽快完全支持。