第二章 线程启动、结束、创建线程多方法

2.1 范例演示线程运行的开始和结束

1、程序运行起来,生成一个进程,该进程所属的主线程开始自动运行

实际上这个是主线程在执行,主线程从main()函数返回,则整个进程执行完毕
2、主线程从main ()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,就代表着我们这个线程运行结束

3、整个进程是否执行完毕的标志是主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了,此时,一般情况下如果其他子线程还没有执行完毕,那么这些子线程也会被操作系统强行终止。所以,一般情况下,我们得到一个结论:如果大家想保持子线程(自己用代码创建的线程)的运行状态的话,那么大家要让主线程一直保持运行,不要让主线程运行完毕

4、创建多线程的方法
(1)包含了thread头文件
(2)初始函数要写
(3)main中开始写代码
大家必须明确一点:有两个线程在跑,相当整个程序的执行有两条线在同时走,所以,可以同时干两个事,即使一条线被堵住了,另外一条线还是可以通行的,这就是多线程

2.1.1 thread

是个标准库里的类

2.1.2 join()

加入/汇合,说白了就是阻塞,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后主线程再往下走。如果主线程执行完毕了,但子线程没执行完毕,这种程序员是不合格的,写出来的程序也是不稳定的,一个书写良好的程序,应该是主线程等待子线程执行完毕后自己才能最终退出

#include <iostream>
#include <thread>

using namespace std;

//自己创建的线程也要从一个函数(初始函数)开始运行
void myPrint()
{
	cout << "子线程工作1" << endl;
	cout << "子线程工作2" << endl;
	cout << "子线程工作3" << endl;
}

int main()
{
	//myPrint可调用对象
	thread myThreadObj(myPrint);  //(1)创建了线程,线程执行起点(入口)是myPrint(); (2)myPrint线程开始执行

	//阻塞主线程并等待myPrint子线程执行完毕
	myThreadObj.join(); //主线程阻塞到这里等待myPrint()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走

	cout << "主线程收尾,最终主线程安全正常退出" << endl;

	system("pause");
	return 0;
}

拓展:两个子线程同时执行,此时都需要用join阻塞主线程

#include <iostream>
#include <thread>

using namespace std;

//自己创建的线程也要从一个函数(初始函数)开始运行
//子线程1
void myPrint1()
{
	cout << "子线程1工作1" << endl;
	cout << "子线程1工作2" << endl;
	cout << "子线程1工作3" << endl;
}

//子线程2
void myPrint2()
{
	cout << "子线程2工作1" << endl;
	cout << "子线程2工作2" << endl;
	cout << "子线程2工作3" << endl;
}

int main()
{
	//myPrint可调用对象
	thread myThread1Obj(myPrint1);  //(1)创建了线程,线程执行起点(入口)是myPrint1(); (2)myPrint1线程开始执行
	thread myThread2Obj(myPrint2);  //(2)创建了线程,线程执行起点(入口)是myPrint2(); (2)myPrint2线程开始执行

	//阻塞主线程并等待子线程执行完毕
	myThread1Obj.join(); //主线程阻塞到这里等待myPrint1()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走
	myThread2Obj.join(); //主线程阻塞到这里等待myPrint2()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走

	cout << "主线程收尾,最终主线程安全正常退出" << endl;

	system("pause");
	return 0;
}

2.1.3 detach()

传统多线程程序主线程要等待子线程执行完毕,然后自己再最后退出,而detach()打破了这种规则,detach分离的意思,也就是主线统程不和子线程汇合了,你主线程执行你的,我子线程执行我的,你主线程也不必等我子线程运,你可以先执行结束,这并不影响我子线程的执行
为什么引入detach(),我们创建了很多子线线程,让主线程逐个等待子线程结束,这种编程方法不太好,所以引入了detach(),好比之前拓展里的写法,就是主线程逐个等待子线程。有的老师说还是建议让主线程逐个等待子线程,以免造成不必要的错误

一旦detach()之后,与这个主线程关联的thread对象就会失去与这个主线程的关联,此时这个子线程就会驻留在后台运行(主线程跟该子线程失去联系)
这个子线程就相当于被c++运行时库接管,当这个子线程执行完成后,由运行时库负责清理该线程相关的资源(守护线程)
detach()使子线程失去我们自己的控制。一旦调用了detach(),就不能再用join),否则系统会报告异常。

#include <iostream>
#include <thread>

using namespace std;

//自己创建的线程也要从一个函数(初始函数)开始运行
void myPrint()
{
	cout << "子线程工作1" << endl;
	cout << "子线程工作2" << endl;
	cout << "子线程工作3" << endl;
}

int main()
{
	//myPrint可调用对象
	thread myThreadObj(myPrint);  //(1)创建了线程,线程执行起点(入口)是myPrint(); (2)myPrint线程开始执行

	//分离主线程和子线程
	myThreadObj.detach();

	cout << "主线程工作1" << endl;
	cout << "主线程工作2" << endl;
	cout << "主线程工作3" << endl;

	system("pause");
	return 0;
}

2.1.4 joinable()

joinable():判断是否可以成功使用join() 或者 detach()的;返回true(可以join或者detach)或者false(不能join或detach)

#include <iostream>
#include <thread>

using namespace std;

//自己创建的线程也要从一个函数(初始函数)开始运行
void myPrint()
{
	cout << "子线程工作1" << endl;
	cout << "子线程工作2" << endl;
	cout << "子线程工作3" << endl;
}

int main()
{
	//myPrint可调用对象
	thread myThreadObj(myPrint);  //(1)创建了线程,线程执行起点(入口)是myPrint(); (2)myPrint线程开始执行
	if (myThreadObj.joinable())
	{
		cout << "1:joinable == true" << endl;
	}
	else
	{
		cout << "1:joinable == false" << endl;
	}
 
	myThreadObj.detach();

	if (myThreadObj.joinable())
	{
		cout << "2:joinable == true" << endl;
	}
	else
	{
		cout << "2:joinable == false" << endl;
	}

	cout << "主线程工作1" << endl;

	system("pause");
	return 0;
}
#include <iostream>
#include <thread>

using namespace std;

//自己创建的线程也要从一个函数(初始函数)开始运行
void myPrint()
{
	cout << "子线程1工作1" << endl;
	cout << "子线程1工作2" << endl;
	cout << "子线程1工作3" << endl;
}

int main()
{
	thread myThreadObj(myPrint);  //(1)创建了线程,线程执行起点(入口)是myPrint(); (2)myPrint线程开始执行
	if (myThreadObj.joinable())
	{
		myThreadObj.join();
	}

	cout << "主线程工作" << endl;

	system("pause");
	return 0;
}

2.2 其它创建线程的手法

2.2.1 用类对象(可调用对象)创建线程

#include <iostream>
#include <thread>

using namespace std;

class TA
{
public:
	void operator()()  //不能带参数
	{
		cout << "我的线程开始执行了" << endl;
		cout << "我的线程执行完毕了" << endl;
	}
};

int main()
{
	TA ta;
	thread myThreadObj(ta);  //ta可调用对象
	myThreadObj.join();      //等待子线程执行结束

	cout << "主线程执行结束!!!" << endl;

	system("pause");
	return 0;
}

大家可能还有一个疑问:一旦调用了detach(),那我主线线程执行结束了,我这里用的这个ta这个对象还在吗?(对象不在了)
这个对象实际上是被复制到线程中去,执行完主线程后,ta会被销毁,但是所复制的TA对象依旧存在。所以,只要你这个TA类对象里没有引用,没有指针,那么就不会产生问题

#include <iostream>
#include <thread>

using namespace std;

class TA
{
public:

	TA()
	{
		cout << "构造函数开始执行" << endl;
	}

	TA(const TA &ta)
	{
		cout << "拷贝构造函数开始执行" << endl;
	}

	~TA()
	{
		cout << "析构函数开始执行" << endl;
	}

	void operator()()  //不能带参数
	{
		cout << "我的子线程开始执行了" << endl;
		cout << "我的子线程执行完毕了" << endl;
	}
};

int main()
{
	TA ta;
	thread myThreadObj(ta);  //ta可调用对象
	//myThreadObj.join();      //等待子线程执行结束
	myThreadObj.detach();

	cout << "主线程执行结束!!!" << endl;

	return 0;
}

2.2.2 用lambda表达式创建线程

#include <iostream>
#include <thread>

using namespace std;

int main()
{
	//lambda表达式
	auto myLambdaThread = [] {
		cout << "我的子线程开始执行" << endl;
		cout << "我的子线程执行结束" << endl;
	};

	thread myThreadObj(myLambdaThread);
	myThreadObj.join();

	cout << "主线程执行结束!!!" << endl;

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值