C++多线程笔记(一)

C++多线程

C++内置的线程库
头文件
#include <thread>

一、
创建一个函数myprint()作为启动线程的内容用:

#include <iostream>
#include <thread>

using namespace std;

// 创建一个函数,作为线程内容
void myprint()
{
	cout << "My thread starts." << endl;


	cout << "My thread ends." << endl;
}

int main()
{

	//thread: 1、创建线程;2、线程开始执行
	thread mytobj(myprint); 

	//join(): 加入/汇合,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后主线程在往下走。
	mytobj.join();//主线程阻塞到这里等待myprint执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走 
	//注释join会报错,原因:可能发生主线程执行完毕,子线程没有执行完,程序不稳定

	cout << "This is the main thread." << endl;
	
	return 0;
}

thread是线程类的名字
1.成员函数join()起到阻塞线程的作用,意思为主线程阻塞到这里等待myprint()执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走 。
运行结果
2.成员函数detach()的作用是,与主线程关联的thread对象就会失去与这个主线程的关联,此时这个子线程就会驻留在后台运行(主线程跟该子线程失去联系)。
**解释:**这个子线程就相当于被c++运行时库接管,档子线程执行完成后,由运行时库负责清理该线程相关的资源(守护线程)。
**注意:**一旦调用了detach(),就不能再join(),则否系统会报告异常
在代码中join()或者detach()一定要有一个,否则会报错。因为当主线程执行完毕时,子线程没有执行完,程序会不稳定。
detach()示例:

#include <iostream>
#include <thread>

using namespace std;

// 创建一个函数,作为线程内容
void myprint()
{
	cout << "My thread starts." << endl;


	cout << "My thread ends." << endl;
}

int main()
{

	//thread: 1、创建线程;2、线程开始执行
	thread mytobj(myprint); 

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

	cout << "This is the main thread." << endl;
	
	return 0;
}

detach示例

3.成员函数joinable()的作用是:判断是否成功使用join()或者detach()的,返回true(可以join或者detach)或者false(不能join,不能detach)
示例:

#include <iostream>
#include <thread>

using namespace std;

// 创建一个函数,作为线程内容
void myprint()
{
	cout << "My thread starts." << endl;


	cout << "My thread ends." << endl;
}

int main()
{

	//thread: 1、创建线程;2、线程开始执行
	thread mytobj(myprint); 
	//在使用join之前加入joinable()判定,观察结果
	if (mytobj.joinable())
	{
		cout << "join() can be used." << endl;
	}
	else
	{
		cout << "join() can not be used." << endl;
	}

	//join(): 加入/汇合,阻塞主线程,让主线程等待子线程执行完毕,然后子线程和主线程汇合,然后主线程在往下走。
	mytobj.join();//主线程阻塞到这里等待myprint执行完,当子线程执行完毕,这个join()就执行完毕,主线程就继续往下走 
	//注释join会报错,原因:可能发生主线程执行完毕,子线程没有执行完,程序不稳定
	
	//在使用join字后加入joinable()判定,观察结果
	if (mytobj.joinable())
	{
		cout << "join() can be used." << endl;
	}
	else
	{
		cout << "join() can not be used." << endl;
	}


	cout << "This is the main thread." << endl;
	
	return 0;
}

结果如图所示
joinable()使用示例
二、类作为线程的可调用对象

#include <iostream>
#include <thread>

using namespace std;

// 二、创建一个类,可调用对象
class TA
{
public:

	void operator()()//重载括号,不能带参数,使类作为一个可调用对象
	{
		cout << "我的线程operator()执行开始了" << endl;
		//...
		cout << "我的线程operator()执行结束了" << endl;

	}

};

int main()
{

	//二、将类对象添加至线程
	TA ta;
	thread mytobj3(ta);
	mytobj3.join();

	cout << "This is the main thread." << endl;
	
	return 0;
}

执行结果
在这里插入图片描述
注意: 若类作为线程的可调用对象,使用detach(),则类的构造函数的参数不能为引用&
构造函数如下:

//构造函数含引用
class TA
{
public:
	TA(int &i):m_i(i) {}
	int &m_i;

	void operator()()//重载括号
	{
		cout << "m_i1的值为:" << m_i << endl;
		cout << "m_i2的值为:" << m_i << endl;
		cout << "m_i3的值为:" << m_i << endl;
		cout << "m_i4的值为:" << m_i << endl;
		cout << "m_i5的值为:" << m_i << endl;
		cout << "m_i6的值为:" << m_i << endl;
	}
};

则程序有可能出现问题,代码见下:

#include <iostream>
#include <thread>

using namespace std;

//构造函数含引用
class TA
{
public:
	TA(int &i):m_i(i) {}
	int &m_i;

	void operator()()//重载括号
	{
		cout << "m_i1的值为:" << m_i << endl;
		cout << "m_i2的值为:" << m_i << endl;
		cout << "m_i3的值为:" << m_i << endl;
		cout << "m_i4的值为:" << m_i << endl;
		cout << "m_i5的值为:" << m_i << endl;
		cout << "m_i6的值为:" << m_i << endl;
	}
};

int main()
{

	int myi = 6;
	//二、将类对象添加至线程
	TA ta(myi);
	thread mytobj3(ta);
	mytobj3.detach();

	cout << "This is the main thread." << endl;
	
	return 0;
}

该种情况:
1.使用detach()当主线程执行完毕后,myi的内存被销毁了,子线程还在打印myi被回收内存的内容,可能会产生不可预料的结果。

2.问:一旦调用了detach(),那主线程执行结束了,这里用的ta这个对象还在吗?答:这个对象实际上是被复制到线程中去;执行完主线程后,ta会被销毁,但是复制的TA对象依旧存在。所以,只要这个TA类对象里没有引用,没有指针,就不会出问题。
改变构造函数,并添加拷贝构造函数来验证:

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

	void operator()()//重载括号
	{
		cout << "m_i1的值为:" << m_i << endl;
		cout << "m_i2的值为:" << m_i << endl;
		cout << "m_i3的值为:" << m_i << endl;
		cout << "m_i4的值为:" << m_i << endl;
		cout << "m_i5的值为:" << m_i << endl;
		cout << "m_i6的值为:" << m_i << endl;
	}
};

全程序:

#include <iostream>
#include <thread>

using namespace std;

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

	void operator()()//重载括号
	{
		cout << "m_i1的值为:" << m_i << endl;
		cout << "m_i2的值为:" << m_i << endl;
		cout << "m_i3的值为:" << m_i << endl;
		cout << "m_i4的值为:" << m_i << endl;
		cout << "m_i5的值为:" << m_i << endl;
		cout << "m_i6的值为:" << m_i << endl;
	}
};

int main()
{

	int myi = 6;
	//二、将类对象添加至线程
	TA ta(myi);
	thread mytobj3(ta);
	mytobj3.detach();

	cout << "This is the main thread." << endl;
	
	return 0;
}

执行结果
在这里插入图片描述
证明TA类的对象ta在被线程调用时被复制了。执行的析构函数是主线程的ta对象
当把mytobj3.detach()替换为mytobj3.join(),运行的结果为:
在这里插入图片描述
析构函数执行了两次,再一次证明了TA类的对象ta在被线程调用时被复制了。第一个析构为线程执行完,线程中ta执行的析构,第二个析构主线程ta对象释放的。

三、用lambda表达式创建线程

#include <iostream>
#include <thread>

using namespace std;

int main()
{

	auto mylamthread = [] {
	cout << "我的线程3开始执行了" << endl;
	//...
	cout << "我的线程3执行结束了" << endl;
	};
	thread myobj4(mylamthread);
	myobj4.join();

	cout << "This is the main thread." << endl;
	
	return 0;
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值