技术标签: C++11技巧
前言:我一直在Windows下开发,所以对Linux下线程的使用不甚了解,不过想来思路是一样的,主要是接口和细节上的差异。我喜欢多线程,主要是可以大幅提高产品的性能。在没有C++11之前,线程开发都是要调用WindowsAPI,还有很多繁琐的参数,线程模式单一,数据传递也不方便。但是C++11的出现,让多线程开发变得非常简单。本文总结一下我在使用C++11线程库中的经验。
一、线程类
头文件:<thread>
类:thread
命名空间:std
thread类是实现多线程的主类,C++11的多线程开发全是围绕thread展开,而条件变量、互斥量都是为线程服务的。
1、线程启动
创建线程对象时向构造函数传入线程函数,线程就会启动
例:void fun(){ printf("working");}
thread(fun).detach();
可以作为线程函数的不止普通函数,还可以是匿名函数、类成员函数、函数对象、function类对象等。
//类成员函数做线程函数
class Task
{
public:
void Working(){ printf("i'm working"); };
};
Task t;
thread thd = thread(&Task::Working, t);
//匿名函数做线程函数
thread thd = thread([](){ printf("i'm working"); });
以上两种方式是最常用的线程函数。
需要注意的是,如果用类成员函数作为线程函数,则第二个参数必须指定相应的类对象。
类成员函数作为线程函数的好处:可以先在类中做其他工作,在必要时才启动线程,而且线程函数不必是静态函数,所以线程函数中可以直接使用当前实例的成员变量和成员函数(这和用静态函数做回调函数不同)。
匿名函数作为线程函数的好处:对于只使用一次的函数,尤其是函数体很小的时候,用匿名函数可以节约代码,清晰代码逻辑,而且匿名函数的过滤条件允许它使用当前类对象的成员变量和/或当前函数的局部变量。
使用匿名函数作为线程函数时必须注意的问题是:如果线程中用到当前函数的局部变量,则因为生命周期的原因,在线程执行过程中,这些局部变量可能已经因为函数执行完毕而被释放,所以匿名函数最好使用类成员变量,因为一般线程的生命周期要小于当前类对象,或者把局部变量作为入参,传入匿名函数。
2、线程传参
线程在启动的时候也可以传递参数,如上例中:
class Task
{
public:
void Working(const string& name){ printf("%s working", name); };
};
Task t;
thread thd = thread(&Task::Working, t, "blwinner");
3、线程停止
线程的停止有两种方式。
方式一:调用thread类成员函数join
join是同步阻塞调用,调用该函数后当前进程被阻塞,直到调用join的线程对象的线程函数执行完毕。
joinable用于判断当前线程是否可以停止。如:
class Task
{
public:
void Working(){ printf("i'm working"); };
};
Task t;
thread thd = thread(&Task::Working, t);
if(thd.joinable()) thd.join();
方式二:自动停止
当启动线程时,调用detach,则线程会被解绑,自行运行到结束。如:
class Task
{
public:
void Working(){ printf("i'm working"); };
};
Task t;
thread(&Task::Working, t).detach();
需要注意的是,一个线程对象,要么被赋予了一个线程实例保存,要么被detach后自行运行结束,如果只是创建线程对象而未保存,或者detach,则线程运行结束后引发错误。如果一个线程被一个线程实例保存,则线程实例的生命周期一定要比线程本身长,否则线程对象在线程运行结束前释放的话,也会引发错误。而如果线程实例保存了线程对象,则实例可以通过以上两种方法来退出线程。
4、线程赋值
线程是不允许拷贝构造的(拷贝构造函数被delete),但是允许赋值操作符“=”,赋值操作符的参数是右值引用。线程对象可以被交换,即通过move(右值引用构造函数)或者std::swap或者thread成员函数swap,所以交换以后,源线程实例就不再持有线程对象,目的线程实例持有线程对象,可以停止线程。所以如果你的类里面有一个thread对象,那么你的类将不能拷贝或普通赋值,解决办法是把用到类对象的时候,把类对象用shared_ptr封装,或者把thread对象用shared_ptr封装(类似的还有mutex对象、条件变量)。
5、辅助函数
在thread类内和std命名空间,提供了几个方便的赋值函数。
1)类内:join,joinable,detach,swap,前文已经介绍过。
还有get_id,获取当前线程ID。hardware_concurrency,获取当前系统进程数,如果系统不支持该查询,可能返回0。
2)类外:this_thread命名空间:函数sleep_for,当前线程睡眠若干时间,可用于异步操作时周期查询,参数必须是chrono对象,如:
this_thread::sleep_for(chrono::seconds(1000));
函数sleep_util,当前线程睡眠到某个时间点,可以用于定时执行,参数必须是chrono的
time_point对象。
yield,当前线程暂停,释放内核资源(如CPU时间片)供其他线程执行一段时间。和sleep不同
之处在于,sleep不会释放内核资源。yield的具体执
行过程,依赖于操作系统的实现。在Linux中,yield后的线程会被加入到同等优先级的线程队列
末尾,如果队列中只有当前一个线程,则yield不会生效。
以上就是C++11中线程库的使用办法和注意事项,后面有时间再补充线程同步的辅助类,
包括mutex相关,条件变量相关,等等。
4G DTU 模块+传感器上传到 OneNET平台 (MQTT新版)智慧农业解决方案在上一篇《Air724 4G模块 DTU ZL-LTE系列 OneNET平台连接教程(MQTT新版)》的基础上,今天介绍DEVELOPLINK设备 DTU ZL-LTE-300 如何通过MQTTS,MODBUS网关功能实现多个传感器接入OneNET平台的智慧农业解决方案。。之面更新阿里云、腾讯云、百度云的接入教程。本文使用到的设备为:DTU ZL-LTE-300、温湿度光照传感器、二氧化碳传感器、氨气传感器——————
1.程序的三大流程在程序开发中,一共有三种流程方式: 顺序:从上向下,顺序执行代码 分支:根据条件判断,决定执行代码的分支 循环:让特定代码重复执行(解决程序员重复工作)2.if语句判断的定义: 如果条件满足,才能做某件事 如果条件不满足,就做另外一件事情,或者什么也不做 正是有了判断,才使得程序世界丰富多彩,充满变化(程序不再从上到下的‘呆 板’执行了) 判断语句...
使类和成员的可访问性最小化区分一个组件设计得好不好,唯一重要的因素在于,它对于外部的其他组件而言,是否隐藏了其内部数据和其他实现细节。尽可能地使每个类或成员不被外界访问。对于顶层的(非嵌套的)类和接口,能做成包级私有的,就应该被做成包级私有(即不加任何修饰符)。这样就可以随心所欲的对其进行修改或删除。如果一个包级私有的顶层类(或接口)只是在某一个类的内部被用到,那就应该考虑使它成为唯一使用...
背景:我在祖国最西边,移动网,网速特别慢,打开CSDN都困难,更别提从pytorch官网下载安装,只能DIY。不是我抱怨,光安装pytorch我花了2天时间。我遇到的问题1.按照官网的方式无法安装pytorch最新版本1.4,pip和conda都不行。我只能去官网按照官网上面的地址,去登陆torch_stable网站(在我这里打开这个网站很慢,我买了阿里云服务器,在服务器...
应用:垃圾邮件分类、主题分类、情感分析workflow:https://developers.google.com/machine-learning/guides/text-classification/model使用字符级 ngram 的词袋模型很有效。不要低估词袋模型,它计算成本低且易于解释。RNN 很强大。但你也可以用 GloVe 这样的外部预训练嵌入套在 RNN 模型上...
/** * 1.1 ts 如何声明一个boolean, number, string类型的值 */// 在js中,定义 isFlag 为true, 但是后面还可以重新给它赋值为字符串,而ts中就不行,同理,声明number, string 也一样let bool: boolean = true;// 会报错:不能将类型“"str"”分配给类型“boolean”。// isFlag = "str"let str: string = "a";// 会报错:不能将类型“1”分配给类型“string
nth-cild(2N+3)表示从第三行开始的奇数行同理 nth-child(2N+4)表示从第四行开始的偶数行nth-cild(2N+5)表示从第五行开始的奇数行
第四章课后习题答案转载于:https://www.cnblogs.com/hhdn/archive/2007/05/13/744537.html
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档。
1.什么是永久代只有 HotSpot 才有 “PermGen space”,而对于其他类型的虚拟机,如 JRockit(Oracle)、J9(IBM) 并没有“PermGen space”。用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和存放Instance的Heap区域不同,所以如果你的APP会load很多class的话
原因用Windows记事本打开并修改.java文件保存后重新编译运行项目出现“Error:(1, 1) java: 非法字符: '\ufeff'”错误,如下图所示: 原来这是因为Windows记事本在修改UTF-8文件时自作聪明地在文件开头添加BOM导致的,所以才会导致IDEA不能正确读取.java文件从而程序出错。解决办法在编辑器IDEA中将文件...
前端页面如下:&lt;% if(@so.hasPermission("user:add")){ %&gt; &lt;!--如果有权限再显示增加按钮--&gt; &lt;button id="add-account" &gt;添加帐号&lt;/button&gt;&lt;% } %&gt;遇到的问题:变量未定义(VAR_NOT_DEFINED):so,后面东改西改的,又遇