c++11 mutex

mutex是多线程编程时经常用到的,在C++11中需要包含<mutex>模块。而在该文件中还有其他和mutex协作的类和函数,使得多线程编程时非常方便。

1 mutex类

mutex对象是一个lockable的对象,当关键区域需要被互斥访问的时候被用来当作信号。mutex对象提供互斥的拥有权限,并且不支持递归。

实际就是mutex是用来进行线程同步的。常用的成员函数有lock()和unlock()

lcok()

调用该函数后,调用函数会锁定mutex,在有些情况下调用函数会阻塞。
1、如果mutex当前没有被任何其他线程locked,则调用线程lock这个mutex对象(从此刻到直到其成员函数unlock被调用,当前线程拥有mutex对象)。
2、如果mutex目前被其他线程locked,则当前线程阻塞直到mutex被其他线程unlock。
3、如果mutex目前被当前线程lock,则会产生死锁错误。大部分情况会崩溃,因为mutex不支持递归。

unlock()

unlock mutex对象,释放mutex对象的所有权。通常和lock成对使用。
调用该函数后,如果有其他线程因为lock同一个mutex对象而阻塞,则他们中的一个会获得mutex的所有权,从而继续执行。

使用案例如下:

不使用mutex同步的情况下:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>

using namespace std;

void fn1()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "线程" << this_thread::get_id() << ":" << "The thread1 is running !" << endl;
	}
}

void fn2()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "线程" << this_thread::get_id() << ":" << "The thread2 is running !" << endl;
	}
}

int main()
{
	thread t1(fn1);
	thread t2(fn2);
	t1.detach();
	t2.detach();

	this_thread::sleep_for(chrono::milliseconds(1000));
	getchar();
	return 0;
}

因为cout是标准输出的接口,所以两个线程同时输出的时候会对cout进行抢占,而两个线程并没有对cout进行同步,所以可能会出现输出错乱的情况。输出结果如下:

在这里插入图片描述
从上图可以看出输出比较杂乱的。

使用mutex对cout进行互斥访问,如下:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>

using namespace std;

mutex mtx;

void fn1()
{
	for (int i = 0; i < 5; i++)
	{
		mtx.lock();
		cout << "线程" << this_thread::get_id() << ":" << "The thread1 is running !" << endl;
		mtx.unlock();
	}
}

void fn2()
{
	for (int i = 0; i < 5; i++)
	{
		mtx.lock();
		cout << "线程" << this_thread::get_id() << ":" << "The thread2 is running !" << endl;
		mtx.unlock();
	}
}

int main()
{
	thread t1(fn1);
	thread t2(fn2);
	t1.detach();
	t2.detach();

	this_thread::sleep_for(chrono::milliseconds(1000));
	getchar();
	return 0;
}

输出如下:

在这里插入图片描述
从上图中可以看出,输出比较工整了,因为我们对cout作了访问保护,当一个线程输出的时候,另一个线程是不能输出的,只有当一个线程输出完毕了,另一个线程才能输出。而这一切是通过mutex来实现的。

除了常用的lock()和unlock()函数之外,还有一个函数可能会用到,那就是 try_lock()

try_lock()

试图去lock mutex对象,但是不会产生阻塞,通常有一下集中情况。

1、如果mutex没有被任何线程lock,则调用线程会lock
2、如果mutex被其他线程lock,则该函数会失败,返回false,但是不会造成阻塞。
3、如果mutex被与调用该函数的线程相同的线程lock,则会产生一个死锁,因为mutex不支持递归,一般情况下会崩溃。

2 unique_lock

在<mutex>文件中除了经常使用的mutex外还有一些其他的与mutex写作的类和函数,其中用的比较多的是unique_lock。

一个unique_lock对象管理一个mutex对象,并且在locked和unlocked两种状态下拥有该对象的唯一所有权。

在构造unique_lock对象时,获取一个mutex对象,并负责该mutex对象的locking和unlocking操作。

unique_lock类保证在析构是unlcok mutex对象(尽管不通过显式调用)。有一点要区分清楚的是unique_lock对象不会管理mutex对象的生命周期,对mutex的所有权一直持续到unique_lock对象被析构。

示例代码如下:

#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>

using namespace std;

mutex mtx;

void fn1()
{
	for (int i = 0; i < 5; i++)
	{
		unique_lock<mutex> lock(mtx);
		cout << "线程" << this_thread::get_id() << ":" << "The thread1 is running !" << endl;
	}
}

void fn2()
{
	for (int i = 0; i < 5; i++)
	{
		unique_lock<mutex> lock(mtx);
		cout << "线程" << this_thread::get_id() << ":" << "The thread2 is running !" << endl;
	}
}

int main()
{
	thread t1(fn1);
	thread t2(fn2);
	t1.detach();
	t2.detach();

	this_thread::sleep_for(chrono::milliseconds(1000));
	getchar();
	return 0;
}

输出结果如下:

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值