C++多线程

线程创建

1.C++11的标准库中的多线程库 #include

2.创建线程的格式 : 关键字thread 线程名(入口函数,入口函数的参数);

若入口函数参数比较多,按照顺序往后写,用英文逗号隔开。

3.子线程开始运行的两张方式:

  • join() 子线程阻塞主线程,子线程运行完之后,主线程再次开始运行;
  • detach() 主线程和子线程同时运行,如果主线程需要使用子线程的数据,在用到子线程数据的地方,子线程还没有运行结束,那么这个时候主线程使用的数据还是子线程最初的数据,由此会产生一些错误,不太建议使用这种方式。

例如:

  • 入口函数:void fun(int a);
  • 创建线程:thread mythread(fun,a);
#include
#include
#include 
using namespace std;
void fun(int a)
{
	cout << "子线程id为" << this_thread::get_id() << endl;
	cout << "子线程睡眠5秒" << endl;
	Sleep(5000);
}
int main()
{
	int a = 10;
	thread mythread(fun, 10);
	cout << "主线程中的子线程id:" << mythread.get_id() << endl;
	cout << "子线程加入:" << endl;
	mythread.join();//主线程被阻塞直至子线程执行结束
    //mythread.detach();//主线程子线程分别执行
	cout << "子线程结束,返回主线程"<< endl;
	return 0;
}

互斥量

1.c++中互斥量是一个类,我们可以理解成是一把锁,在一些需要互斥使用的临界区(代码段)加上锁,锁住的代码区域要适中,太少起步到保护效果,太多会影响运行效率;

2.互斥量的头文件  #include

3.互斥量的创建    mutex m; 这个m是创建的类对象,mutex为类名;

4.lock()和unlock()要成对使用;

#include
#include
#include 
#include
using namespace std;

mutex m;
int a = 1;

void fun1()
{
	m.lock();
	cout << "thr1拿到锁:" << endl;
	cout << "原参数值" << a << endl;
	cout << "现参数值" << ++a << endl;
	m.unlock();
}

void fun2()
{
	m.lock();
	cout << "thr2拿到锁:" << endl;
	cout << "原参数值" << a << endl;
	cout << "现参数值" << --a << endl;
	m.unlock();
}
int main()
{

	thread thr1(fun1);
	thread thr2(fun2);
	//下面两个线程同时加入,但是执行顺序可能thr1在前,也可能thr2在前
	//所以执行结果也有多种
		//thr1拿到锁:
		//原参数值1
		//现参数值2
		//thr2拿到锁:
		//原参数值2
		//现参数值1
	//或
		//thr2拿到锁:
		//原参数值1
		//现参数值0
		//thr1拿到锁:
		//原参数值0
		//现参数值1
	thr1.join();
	thr2.join();
	return 0;
}

为避免lock()之后忘记unlock(),造成临界区一直被锁,产生了类似于智能指针的两种方式

lock_guard

1.原理:构造函数中lock(),析构函数中unlouck();

2.可以通过使用{}来调整lock()的作用域范围,让互斥量m在合适的地方被解锁

3.使用lock_guard后不能手动lock()与手动unlock();如果lock_guard加了adopt_lock参数,表示构造函数中不再加锁,需要提前手动加锁。用std::adopt_lock的前提是,自己需要先把mutex lock上;

   例如:m.lock();//手动锁定,m为mutex的类对象

              lock_guard lockg(m,adopt_lock);

4. lock_guard不可以复制也不可以转移(move)

          

#include
#include
#include 
#include
using namespace std;

mutex m;
int a = 1;

void fun1()
{
	lock_guard lockg1(m);
	cout << "thr1拿到锁:" << endl;
	cout << "原参数值" << a << endl;
	cout << "现参数值" << ++a << endl;
}

void fun2()
{
	m.lock();//先手动锁定,才能再使用unique_lock的adopt_lock参数
	lock_guard lockg2(m, adopt_lock);
	cout << "thr2拿到锁:" << endl;
	cout << "原参数值" << a << endl;
	cout << "现参数值" << --a << endl;
}
int main()
{

	thread thr1(fun1);
	thread thr2(fun2);
	//下面两个线程同时加入,但是执行顺序可能thr1在前,也可能thr2在前
	//所以执行结果也有多种
		//thr1拿到锁:
		//原参数值1
		//现参数值2
		//thr2拿到锁:
		//原参数值2
		//现参数值1
	//或
		//thr2拿到锁:
		//原参数值1
		//现参数值0
		//thr1拿到锁:
		//原参数值0
		//现参数值1
	thr1.join();
	thr2.join();
	return 0;
}

unique_lock

1.于功能上unique_lock类似于lock_guard,但是unique_lock的功能更强大一些,用法上也更灵活一些,但是比lock_guard要慢一些,内存占用多一些;

2.与lock_guard不同的是,使用unique_lock后可以手动lock()与手动unlock();

3.unique_lock的参数有adopt_lock、try_to_lock、defer_lock

  • adopt_lock:用std::adopt_lock的前提是,自己需要先把mutex lock上;
  • try_to_lock:尝试加锁,尝试失败就立即返回,用这个try_to_lock的前提是你自己不能先lock
  • defer_lock:初始化了一个没有加锁的mutex,用std::defer_lock的前提是,你不能自己先lock,否则会报异常

4. unique_lock的成员函数 lock()、unlock()、try_lock()、release()

 lock():加锁

 lunlock():解锁

 try_lock():尝试给互斥量加锁,如果拿不到锁,返回false,如果拿到了锁,返回true,这个函数是不阻塞的

release():返回它所管理的mutex对象指针,并释放所有权;也就是说,这个unique_lock和mutex不再有关系。

5. unique_lock不可以复制,可以把所有权转移给其他锁(move)

例如:

unique_lock g1(m,defer_lock);

unique_lock g2(move(g1));//所有权转移,此时由g2来管理互斥量m

#include
#include
#include 
#include
using namespace std;

mutex m;
int a = 1;

void fun1()
{
	unique_lock lockg1(m, defer_lock);//初始化一个没有加锁的mutex
	lockg1.lock();//unique_lock加锁,不是m.lock();
	cout << "fun1拿到m锁:" << endl;
	cout << "原参数值" << a << endl;
	cout << "现参数值" << ++a << endl;
	//lockg1.unlock();

}

void fun2()
{
	unique_lock lockg2(m, try_to_lock);//尝试拿锁,只尝试一次,如果没拿到就返回,不会导致本线程一直阻塞在lock这里。

	if (lockg2.owns_lock())
	{
		cout << "fun2拿到m锁:" << endl;
		cout << "原参数值" << a << endl;
		cout << "现参数值" << --a << endl;
	}
	else
	{
		cout << "fun2没有拿到m锁" << endl;
	}


}
int main()
{

	thread thr1(fun1);
	thread thr2(fun2);
	//下面两个线程同时加入,但是执行顺序可能thr1在前,也可能thr2在前
	//所以执行结果也有多种:
		/*fun2拿到m锁:
		原参数值1
		现参数值0
		fun1拿到m锁:
		原参数值0
		现参数值1*/
	//或
		//fun2没有拿到m锁fun1拿到m锁:
		//原参数值
		//1
		//现参数值2
	//或
		//fun1拿到m锁:fun2没有拿到m锁

		//原参数值1
		//现参数值2
	thr2.join();
	thr1.join();
	return 0;
}

你可能感兴趣的:(C++,多线程,c++,多线程)