C++并发与多线程(一)

第一节 并发基本概念及实现, 进程 线程基本概念

一 并发线程 进程的基本概念和综述

1.1 并发:

两个或者更多的任务(独立的活动)同时发生:一个程序同时执行多个独立任务。
单核cpu,某一时刻只能执行一个任务,由操作系统调度,每秒钟进行多次所谓的“任务切换”。
假象(不是真正的并发))这种切换(上下文切换)是要有时间开销的。

1.2 可执行程序

例如windows下的exe文件

1.3 进程

一个可执行程序运行以后即创建了一个进程。
运行起来的可执行文件叫做一个进程。

1.4 线程

每个进程都有一个主线程,主线程唯一。
进程存在,主线程自动存在,所以一个进程中至少含有一个主线程。
运行程序时,实际是进程的主线程来运行。共存关系。
线程:执行代码,理解成一条代码的执行路径。
除主线程外,可以通过自己写代码来创建其他线程。
在这里插入图片描述
每创建一个新线程,可以在同一时刻做不同的事
多线程:线程并不是越多越好,每个线程都需要一个独立的堆栈空间,线程的切换要保存很多中间状态,会耗费本该属于程序运行的时间。
线程的优点:速度快,轻量级,系统资源开销更少,执行速度更快,通信快。
缺点:有难度,要小心处理数据一致性问题。

二 .并发的实现方法

(1)实现方法一:多进程实现并发

进程间的通讯:管道 文件 消息队列 共享内存
不同电脑通信:socket

(2)多线程并发

在单独的进程中,创建多个线程实现并发。
每个线程有自己独立的路径,一个进程中的所有线程共享地址内存,带来了数据一致性问题。
全局变量,指针,引用都可以在线程之间传递。
多线程开销远小于多进程。
优先考虑多线程,只谈多线程并发。

三 .C++新标准线程

以往的多线程代码不可跨平台:
window:CreateThread(), _beginthread() ,beginthread()创建线程
Linux:pthread_create() 创建线程。

POSIX thread(pthread) 可以实现跨平台,但配置繁琐。
C++11新标准增加对多线程的支持,可移植(跨平台)

第二节 线程启动、结束,创建线程、join,detach

一 范例延时线程运行的开始和结束

1.1 thread类

thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行

1.2 join()函数

join函数阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程。

myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出

下面这张图描述了主线程与子线程的通道状态,main和myprint在两个不同的线路中,如果main结束,则myprint一般情况下会被强行终止,但也有例外,下面的detach函数可以让主线程早于子线程结束。
主线程与子线程

1.3 detach()函数

传统多线程程序主线程要等待子线程再结束 ,detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序。

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

void myprint()
{
	cout << "我的线程开始了" << endl;
	cout << "我的线程结束了1" << endl;
	cout << "我的线程结束了2" << endl;
	cout << "我的线程结束了3" << endl;
	cout << "我的线程结束了4" << endl;
	cout << "我的线程结束了5" << endl;
	cout << "我的线程结束了6" << endl;
	cout << "我的线程结束了7" << endl;


}

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	myobj.detach();
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " 主线程完毕 !" << endl;

	
	return 0;
}

在这里插入图片描述

1.4 joinable()函数

判断是否可以成功使用joinable或者detach ,返回true或者false。

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

void myprint()
{
	cout << "我的线程开始了" << endl;
	cout << "我的线程结束了1" << endl;
	cout << "我的线程结束了2" << endl;
	cout << "我的线程结束了3" << endl;
	cout << "我的线程结束了4" << endl;
	cout << "我的线程结束了5" << endl;
	cout << "我的线程结束了6" << endl;
	cout << "我的线程结束了7" << endl;


}

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
		cout << "1.joinable =true" << endl;
	else
		cout << "1.joinable =false" << endl;

	myobj.detach();


	if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
		cout << "2.joinable =true" << endl;
	else
		cout << "2.joinable =false" << endl;
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " 主线程完毕 !" << endl;

	
	return 0;
}


在这里插入图片描述

判断可以加入阻塞函数后,加入阻塞函数。

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

void myprint()
{
	cout << "我的线程开始了" << endl;
	cout << "我的线程结束了1" << endl;
	cout << "我的线程结束了2" << endl;
	cout << "我的线程结束了3" << endl;
	cout << "我的线程结束了4" << endl;
	cout << "我的线程结束了5" << endl;
	cout << "我的线程结束了6" << endl;
	cout << "我的线程结束了7" << endl;


}

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	{
		cout << "1.joinable =true" << endl;

		myobj.join();
	}
	else
		cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
	//	cout << "2.joinable =false" << endl;
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " i love china !" << endl;
	cout << " 主线程完毕 !" << endl;

	
	return 0;
}

在这里插入图片描述

二 其他创建线程的方法

1.用类对象

示例:

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

//void myprint()
//{
//	cout << "我的线程开始了" << endl;
//	cout << "我的线程结束了1" << endl;
//	cout << "我的线程结束了2" << endl;
//	cout << "我的线程结束了3" << endl;
//	cout << "我的线程结束了4" << endl;
//	cout << "我的线程结束了5" << endl;
//	cout << "我的线程结束了6" << endl;
//	cout << "我的线程结束了7" << endl;
//
//
//}

class TA
{
public:
	void operator()() //不能带参数 重载()调用对象就是调用函数
	{
		cout << "我的线程operator开始了" << endl;
	    cout << "我的线程operator结束了" << endl;
	
	}

};

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程方法1  thread调用函数
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	//thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//{
	//	cout << "1.joinable =true" << endl;

	//	myobj.join();
	//}
	//else
	//	cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
		cout << "2.joinable =false" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;

	//创建子线程方法2  thread调用类对象(可调用对象)

	TA ta;
	thread myobj(ta);
	myobj.join();   


	cout << " 主线程完毕 !" << endl;

	return 0;
}

在这里插入图片描述

使用类对象创建多线程时,如果使用detach会出现问题:当构造函数采用引用传递时,构造函数中如果使用了局部变量,主线程结束时,局部变量的地址被回收,打印出的结果不可预料。


#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

//void myprint()
//{
//	cout << "我的线程开始了" << endl;
//	cout << "我的线程结束了1" << endl;
//	cout << "我的线程结束了2" << endl;
//	cout << "我的线程结束了3" << endl;
//	cout << "我的线程结束了4" << endl;
//	cout << "我的线程结束了5" << endl;
//	cout << "我的线程结束了6" << endl;
//	cout << "我的线程结束了7" << endl;
//}

class TA
{
public:
	int &mi;
	TA(int &i) :mi(i) {}
	void operator()() //不能带参数 重载()调用对象就是调用函数
	{
		/*cout << "我的线程operator开始了" << endl;
	    cout << "我的线程operator结束了" << endl;*/

		cout << "mi1的值为:" <<mi<<endl;
		cout << "mi2的值为:" << mi<< endl;
		cout << "mi3的值为:" <<mi<< endl;
		cout << "mi4的值为:" << mi<<endl;
	}

};

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程方法1  thread调用函数
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	//thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//{
	//	cout << "1.joinable =true" << endl;

	//	myobj.join();
	//}
	//else
	//	cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
		cout << "2.joinable =false" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;


	//创建子线程方法2  thread调用类对象(可调用对象)
	int mii = 6;
	TA ta(mii);

	thread myobj(ta);
	myobj.detach();   

	cout << " 主线程完毕 !" << endl;

	return 0;
}



在这里插入图片描述
在这里插入图片描述

使用对象创建子线程时,thread调用对象时使用了拷贝构造函数,对象被复制到线程中去,如果对象没使用引用或指针,就不会出现问题。下面验证thread调用了对象的拷贝构造函数。

下面是使用detach验证

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

//void myprint()
//{
//	cout << "我的线程开始了" << endl;
//	cout << "我的线程结束了1" << endl;
//	cout << "我的线程结束了2" << endl;
//	cout << "我的线程结束了3" << endl;
//	cout << "我的线程结束了4" << endl;
//	cout << "我的线程结束了5" << endl;
//	cout << "我的线程结束了6" << endl;
//	cout << "我的线程结束了7" << endl;
//}

class TA
{
public:
	int mi;
	TA(int i) :mi(i)
	{
		cout << "TA()构造函数被执行" << endl;
	
	}
	TA(const TA&ta) :mi(ta.mi)
	{
		cout << "TA()拷贝构造函数被执行" << endl;
	}
	~TA()
	{
		cout << "析构函数被执行" << endl;
	}

	void operator()() //不能带参数 重载() 作为可调用对象
	{
		/*cout << "我的线程operator开始了" << endl;
	    cout << "我的线程operator结束了" << endl;*/

		cout << "mi1的值为:" <<mi<<endl;
		cout << "mi2的值为:" << mi<< endl;
		cout << "mi3的值为:" <<mi<< endl;
		cout << "mi4的值为:" << mi<<endl;
	}

};

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程方法1  thread调用函数
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	//thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//{
	//	cout << "1.joinable =true" << endl;

	//	myobj.join();
	//}
	//else
	//	cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
		cout << "2.joinable =false" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;


	//创建子线程方法2  thread调用类对象(可调用对象)
	//如果使用类对象创建子线程并调用了detach,主线程结束后,对象还在吗?
	//对象不在了,但是对象时被复制到了线程中去,原对象被销毁但复制的对象还在,如果对象中不存在引用和指针,就不会出问题
	int mii = 6;
	TA ta(mii);

	thread myobj(ta);
	myobj.detach();   

	cout << " 主线程完毕 !" << endl;

	return 0;
}



在这里插入图片描述

下面使用join函数做对比验证

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

//void myprint()
//{
//	cout << "我的线程开始了" << endl;
//	cout << "我的线程结束了1" << endl;
//	cout << "我的线程结束了2" << endl;
//	cout << "我的线程结束了3" << endl;
//	cout << "我的线程结束了4" << endl;
//	cout << "我的线程结束了5" << endl;
//	cout << "我的线程结束了6" << endl;
//	cout << "我的线程结束了7" << endl;
//}

class TA
{
public:
	int &mi;
	TA(int &i) :mi(i)
	{
		cout << "TA()构造函数被执行" << endl;
	
	}
	TA(const TA&ta) :mi(ta.mi)
	{
		cout << "TA()拷贝构造函数被执行" << endl;
	}
	~TA()
	{
		cout << "析构函数被执行" << endl;
	}

	void operator()() //不能带参数 重载() 作为可调用对象
	{
		/*cout << "我的线程operator开始了" << endl;
	    cout << "我的线程operator结束了" << endl;*/

		cout << "mi1的值为:" <<mi<<endl;
		cout << "mi2的值为:" << mi<< endl;
		cout << "mi3的值为:" <<mi<< endl;
		cout << "mi4的值为:" << mi<<endl;
	}

};

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

	//创建子线程方法1  thread调用函数
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	//thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//{
	//	cout << "1.joinable =true" << endl;

	//	myobj.join();
	//}
	//else
	//	cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
		cout << "2.joinable =false" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;


	//创建子线程方法2  thread调用类对象(可调用对象)
	//如果使用类对象创建子线程并调用了detach,主线程结束后,对象还在吗?
	//对象不在了,但是对象时被复制到了线程中去,原对象被销毁但复制的对象还在,如果对象中不存在引用和指针,就不会出问题
	int mii = 6;
	TA ta(mii);

	thread myobj(ta);
	//myobj.detach();  
	myobj.join();

	cout << " 主线程完毕 !" << endl;

	return 0;
}

在这里插入图片描述

2.用lambda表达式

#include "pch.h"
#include <iostream>
#include <thread>
using namespace std;

//void myprint()
//{
//	cout << "我的线程开始了" << endl;
//	cout << "我的线程结束了1" << endl;
//	cout << "我的线程结束了2" << endl;
//	cout << "我的线程结束了3" << endl;
//	cout << "我的线程结束了4" << endl;
//	cout << "我的线程结束了5" << endl;
//	cout << "我的线程结束了6" << endl;
//	cout << "我的线程结束了7" << endl;
//}

class TA
{
public:
	int &mi;
	TA(int &i) :mi(i)
	{
		cout << "TA()构造函数被执行" << endl;
	
	}
	TA(const TA&ta) :mi(ta.mi)
	{
		cout << "TA()拷贝构造函数被执行" << endl;
	}
	~TA()
	{
		cout << "析构函数被执行" << endl;
	}

	void operator()() //不能带参数 重载() 作为可调用对象
	{
		/*cout << "我的线程operator开始了" << endl;
	    cout << "我的线程operator结束了" << endl;*/

		cout << "mi1的值为:" <<mi<<endl;
		cout << "mi2的值为:" << mi<< endl;
		cout << "mi3的值为:" <<mi<< endl;
		cout << "mi4的值为:" << mi<<endl;
	}

};

int main()
{
	cout << " i love china !" << endl;
	//个主线程在执行,主线程从main函数返回,整个进程执行完毕

	//主线程从main函数执行,自己创建的函数,也需要一个函数开始运行(初始函数),一旦这个函数运行完毕,线程结束	
	//这个进程是否执行完毕的标志是主线程是否完毕,如果主线程执行完毕了,就代表整个进程执行完毕
	//如果子线程还没有执行完,那么这些子线程也会被操作系统强行终止。
	//一般情况下,想保持子线程(自己创建的线程)运行的话,需要让主线程一直运行,有例外情况

/***********************************************************************/
	//创建子线程方法1 thread调用函数
	//1.头文件thread    标准库中的类
	//2.创建函数
	//3.main中写代码

	//这段代码是两个线程在走,同时做两件事 即使一条线被堵住了,另一条线还可以运行
	//thread myobj(myprint);			  //myprint 为可调用对象         此代码(1)创建线程,线程入口 myprint函数(2)myprint线程开始执行
	
	//myobj.join();					 //join阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,再继续走主线程	
	//如果不阻塞 主线程会早于子线程完成,子线程被强制终止 
	//良好的程序应该主线程等待子线程完毕后才退出


	//detach():传统多线程程序主线程要等待子线程再结束  detach函数使主线程不等待子线程运行,可以早于子线程结束,各自执行各自的程序
	//引入原因:线程过多,主线程一直等待 
	//一旦detach(),主线程与子线程失去联系,子线程在后台运行,子线程被系统接管,子线程执行完毕后,由运行时库负责清理线程相关资源。
	//更推荐join()  一旦detach,不能再用join

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//{
	//	cout << "1.joinable =true" << endl;

	//	myobj.join();
	//}
	//else
	//	cout << "1.joinable =false" << endl;

	//if (myobj.joinable()) //判断是否可以成功使用joinable或者detach  返回true或者false
	//	cout << "2.joinable =true" << endl;
	//else
		cout << "2.joinable =false" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;
	//cout << " i love china !" << endl;

/***********************************************************************/
	//创建子线程方法2  2.1thread调用类对象(可调用对象)
	//如果使用类对象创建子线程并调用了detach,主线程结束后,对象还在吗?
	//对象不在了,但是对象时被复制到了线程中去,原对象被销毁但复制的对象还在,如果对象中不存在引用和指针,就不会出问题
	//int mii = 6;
	//TA ta(mii);

	//thread myobj(ta);
	myobj.detach();  
	//myobj.join();


	//2.2使用lambda表达式
	auto lamthread = []
	{
		cout << "我的线程lambda开始了" << endl;
		cout << "我的线程lambda结束了" << endl;
	
	};
	thread myobj(lamthread);

	myobj.join();

	cout << " 主线程完毕 !" << endl;

	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael.Scofield

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值