c++11多线程(1)

C++11对多线程的支持

c++11中新支持了thread这个库,常见的创建线程、join()、detach()都能支持。所以我们能写出跨平台的多线程程序了。

进程和线程

在我们运行一个程序的时候,像我们写的一个cpp控制台程序运行起来,它就是一个进程。计算机运行可以有多个进程,进程里面也可以有多个线程,我们最熟悉的一个线程就是main()这个主线程了,主线程结束运行,这个进程也就结束了。

进程 是操作系统动态执行的基本单元,它可以被描述成一段程序的执行过程。进程之间资源不共享。
线程是操作系统工作的最小单元,创建线程可以有效提高效率,可以利用多核优势,对io密集型优化明显,程序可以在io的时候让另一个线程干其他事。线程之间资源共享

创建一个线程

接下来我们就用C++11提供的线程库thread创建一个线程。

#include <iostream> 
#include <thread>	//C++11线程库头文件

using namespace std;

void my_thread(int num){
	cout << "you create a thread!" << num<<  endl;
	cout << "the thread id is:" << std::this_thread::get_id() << endl;
	return;
}
int main(){
	cout << "main's thread id is:" << std::this_thread::get_id() << endl;
	thread thread_oj(my_thread,1);		//第一个参数为线程入口函数,第二个参数为线程入口函数的参数。	
	thread_oj.join();		//将创建的线程插入主线程的执行队列,并阻塞主线程,等待该线程执行完再放开。
	//thread_oj.detach();		//将创建的线程交由C++运行时库掌管,不阻塞主线程。
	return 0;
}

运行结果:运行结果

函数浅析

上面我们用C++11的多线程库thread创建了一个线程,肯定有人说:“空口无凭,你怎么敢假定你创建了一个线程呢?” 在上面,我们用了一个函数来验证我们有没有创建线程。

==std::this_thread::get_id()==它的作用是取得它所在运行的线程的id,每个线程都有一个id唯一标识。我们知道,本来该程序是肯定只有一个main()作为主线程的。我们在主线程中放了一个get_id,在我们的所谓线程入口函数里也放了一个get_id,运行结果告诉我们它们并不相同,所以,我们的的确确是创建了一个线程。

==thread thread_oj(可调用对象,[对象的参数])==它的作用是创建一个线程,它有一个参数和多个可选参数,可选参数数量由第一个参数决定。

  1. 它第一个参数是一个可调用对象,用来作为线程入口函数。创建一个线程,肯定要有它应该要执行的动作,所以该线程将会执行该可调用对象内的语句。除了自定义函数以外,lambda,类的成员函数也是可以作为线程入口函数的。例:==thread myobj5(&A::thread_work, obj, 14);==它用一个名字为A的类的 thread_work(int var) 函数来创建了一个线程。
    2.除了第一个参数外,其他参数都是可选参数,要根据线程入口函数的样式来填入。

==thread_oj.join()==它的作用是将我们创建的线程插入线程运行队列,并阻塞主线程,等我们创建的线程执行完再放开。

==thread_oj.detach()==当thread对象使用detach之后,它会失去与主线程的关联,它会被C++运行时库接管,在后台运行,当它执行完毕,由运行时库释放该线程占用的资源,虽然它不归主线程管,但是若主线程退出,它的执行也将结束。(会造成乱序执行,严重会崩溃,可能主线程退出了,但它还没开始运行,它的运行结果不会显示给我们)调用detach之后不能再调用join了

传值陷阱

1.在我们给线程传入一个临时对象作为线程参数时,thread会粗暴的将它进行拷贝复制,将复制后的值传入线程(如果是传入的指针对象,它不会使用拷贝)。如果我们的线程要处理一个在主线程中的临时变量,它可能并不会对主线程中的临时变量产生影响。

2.在线程创建的时候,如果我们使用主线程中的临时变量来构造我们的临时对象,而且该线程调用了detach时。若主线程先执行完了,临时变量已经被回收,那么线程构造调用临时变量时,将拿不到临时变量,将导致未定义的行为,可能产生危险。

注:使用主线程中的临时变量来构造我们的临时对象,临时对象的构造是在子线程中完成构造的。若通过临时变量先生成临时对象,则构造过程是在主线程中完成的

解决方法:在创建线程传入参数的时候,将临时变量预先进行类型转换,直接构造临时对象,这样就可以保证不会出现危险。(detach很容易导致危险行为,尽量少用)。

总结

1:若传递简单类型对象,建议值传递,用引用会导致节外生枝
2:若传递类对象等复杂对象,要避免隐式类型转换,要转换好(转换方式自便),构建出临时对象,然后再函数参数里用引用接受对象,
减少thread函数构造次数
3:尽量避免使用detach,避免临时变量被释放导致出现未定义行为,join多好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值