700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法

为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法

时间:2022-02-09 15:33:09

相关推荐

为什么不能线程调用类的成员函数_C++多线程编程之创建线程的几种方法

点蓝色字关注“CurryCoder的程序人生”

微信公众号:CurryCoder的程序人生

怕什么真理无穷,进一寸有一寸的欢喜

1.线程基础知识

可执行程序运行起来,就会生成一个进程,该进程所属的主线程开始自动运行。请看下面的示例程序:

#include

usingnamespacestd;

intmain(){

cout<"IloveChina!"<endl;//实际上这个是主线程在执行,主线程从main()函数返回,则整个进程执行完毕。

return0;

}

主线程从main()函数开始执行,当我们自己创建线程时,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,就代表我们这个线程运行结束。整个进程是否执行完毕的标志主线程是否执行完,如果主线程执行完毕,就代表整个进程执行完毕。此时,如果其他子线程还没有执行完,那么这些子线程也会被操作系统强行终止。因此,一般情况下,如果想保持子线程(自己用代码创建的线程)的运行状态,则必须要让主线程一直保持运行,不要让主线程运行结束。2.创建线程的几种常用方法2.1使用初始函数创建线程主要流程如下:包含一个头文件thread编写初始函数在main()函数中开始写代码

#include

#include

usingnamespacestd;

//自己创建的线程也要从一个函数(初始函数)开始运行

voidmyprint(){

cout<"我的线程开始执行了\n";

/*

中间包含其他的业务逻辑代码

*/

cout<"我的线程执行完毕了\n";

}

intmain(){

threadmytobj(myprint);

mytobj.join();

cout<"IloveChina!"<endl;

return0;

}

观察上面的代码发现:有两个线程在运行,相当于整个程序的执行有两条线在同时走。所以可以同时干两件事。即使一条线被堵住了,另外一条线仍然是可以通行的,这就是多线程。

(1).thread:是标准库中的类

//myprint是可调用对象

threadmytobj(myprint);

}

上面的代码段做了两件事:a.创建了线程,线程执行起点(入口)myprint();b.myprint线程开始执行(2).join()加入/汇合,简单来说就是阻塞。阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合。然后主线程再继续往下走!

threadmytobj(myprint);

mytobj.join();

上面代码段的分析:a.主线程阻塞到这里等待myprint子线程执行完,当子线程执行完毕,这个join()就执行完毕,主线程再继续往下执行。换言之,即阻塞主线程并等待myprint()子线程执行完。b.如果主线程执行完毕,但子线程没执行完毕,这样的程序是不合格的!程序也是不稳定的。一个良好的程序,应该是主线程等待子线程执行完毕后,主线程才能最终退出(3).detach()detach()函数即主线程不再和子线程汇合。主线程执行自己的,子线程也执行自己的,主线程也不必等待子线程运行结束。主线程可以先执行结束,这并不影响子线程的执行。由于我们创建了很多子线程,让主线程逐个等待子线程结束,这种方法不太好,所以引入detach()方法。一旦detach()之后,与主线程关联的thread对象就会失去与主线程的关联性。此时,子线程就会驻留在后台运行了(主线程与该子线程失去联系),子线程就相当于被C++运行时库接管。当子线程执行完毕后,由运行时库负责清理该线程相关的资源(守护线程)。detach()使线程myprint失去我们对其进行的控制。一旦调用了detach(),就不能再用join(),否则系统会报告异常(4).joinable()判断是否可以成功使用join()或者detach()。若返回true,则可以使用join或者detach。否则,则不能使用。

threadmytobj(myprint);

if(mytobj.joinable())

{

cout<"1:joinable()==true"<endl;

}

else

{

cout<"1:joinable()==false"<endl;

}

mytobj.detach();//阻塞主线程并等待myprint()子线程执行完

if(mytobj.joinable())

{

cout<"2:joinable()==true"<endl;

}

else

{

cout<"2:joinable()==false"<endl;

}

2.2使用类对象创建线程

#include

#include

usingnamespacestd;

classTA

{

public:

voidoperator()()//类对象变成可调用对象,即后面的括号中不能带参数{

cout<"我的线程operator()开始执行了\n";

/*

中间包含其他的业务逻辑代码

*/

cout<"我的线程operator()结束执行了\n";

}

};

intmain(){

TAta;//ta是一个类的对象

threadmytobj3(ta);//同时,ta也是一个可调用对象

mytobj3.join();//等待子线程执行结束

cout<"ILoveChina"<endl;

return0;

}

使用类对象创建线程的代码如上所示,但需要注意一个问题。请看如下代码

#include

#include

usingnamespacestd;

classTA

{

public:

int&m_i;

TA(int&i):m_i(i){}

voidoperator()()//类对象变成可调用对象,即后面的括号中不能带参数{

cout<"m_i1的值为:"<endl;//产生不可意料的结果!

cout<"m_i2的值为:"<endl;

cout<"m_i3的值为:"<endl;

cout<"m_i4的值为:"<endl;

cout<"m_i5的值为:"<endl;

cout<"m_i6的值为:"<endl;

}

};

intmain(){

intmyi=6;

TAta(myi);//ta是一个类的对象

threadmytobj3(ta);//同时,ta也是一个可调用对象

//mytobj3.join();//等待子线程执行结束

mytobj3.detach();

cout<"ILoveChina"<endl;

return0;

}

分析上述代码的输出结果可知:由于使用了mytobj3.detach(),因此主线程与子线程之间是无关的。主线程执行主线程的,子线程执行子线程的。现在假设出现一种情况,主线程先执行完了,子线程后执行完的。由于子线程的函数中使用的是引用成员变量m_i,m_i是与形参引用变量i绑定在一起的。而形参变量i是主线程中实参myi的引用,myi是主线程中的局部变量,当主线程执行结束后,变量myi的内存空间就会被系统所回收。但是,子线程仍然没有执行完,还在打印已经被销毁的变量m_i的内容,那么就会产生不可意料的结果了。

对上述代码段还有一个疑问:一旦调用了detach(),当主线程执行结束了,主线程中用的这个ta对象还存在吗?答:这个ta对象已经不存在了,因为这个对象ta实际上是被复制到子线程中去的!所以执行完主线程后,ta对象会被销毁,但是所复制的ta对象依旧存在。所以,只要你这个TA类对象里没有引用、没有引用,那么就不会产生问题。验证代码如下所示:

#include

#include

usingnamespacestd;

classTA

{

public:

int&m_i;

TA(int&i):m_i(i){

cout<"TA构造函数被执行"<endl;

}

TA(constTA&ta):m_i(ta.m_i)

{

cout<"TA()拷贝构造函数被执行"<endl;

}

~TA()

{

cout<"TA()析构函数被执行"<endl;

}

voidoperator()()//类对象变成可调用对象,即后面的括号中不能带参数{

cout<"m_i1的值为:"<endl;

cout<"m_i2的值为:"<endl;

cout<"m_i3的值为:"<endl;

cout<"m_i4的值为:"<endl;

cout<"m_i5的值为:"<endl;

cout<"m_i6的值为:"<endl;

}

};

intmain(){

intmyi=6;

TAta(myi);//ta是一个类的对象

threadmytobj3(ta);//同时,ta也是一个可调用对象

//mytobj3.join();//等待子线程执行结束

mytobj3.detach();

cout<"ILoveChina"<endl;

return0;

}

2.3使用lambda表达式创建线程

intmain(){

automylamthread=[]

{

cout<"我的线程3开始执行了"<endl;

//...

cout<"我的线程3执行结束了"<endl;

};

threadmytobj4(mylamthread);

mytobj4.join();

return0;

}

觉得不错,请一键三连吧↓

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。