C++ mutex和lock

mutex用来协助采取独占方式控制对资源的并发访问,这里的资源可能是一个对象,或多个对象的组合,为了获得独占式的资源访问能力,相应的线程必须锁定mutex,这样可以防止其它线程也锁定该mutex。

下面两条线程如果没有使用mutex来同步,则输出结果会是112233。

mutex g_mutex;

void print123() 
{
	g_mutex.lock();
	for (int i = 0; i < 3; i++) {
		this_thread::sleep_for(chrono::milliseconds(100));
		cout << i + 1;
	}
	g_mutex.unlock();
}
 
int main()
{
	thread(print123).detach();
	thread(print123).detach();//123123
	system("pause");
}

你应该确保mutex对象调用lock后,即使发生异常也会调用unlock,否则有可能造成资源被永远锁住或者死锁。

为此我们可以使用lock_guard来进行lock和unlock,lock_guard在构造时会lock,析构时会unlock,使用大括号对可以加快lock_guard的析构,需要注意的是lock_guard一定要分配变量名,否则不会有效果。
 

void print123()
{
	lock_guard<mutex> lockGuard(g_mutex);
	for (int i = 0; i < 3; i++) {
		this_thread::sleep_for(chrono::milliseconds(100));
		cout << i + 1;
	}
}

同一线程多次锁定mutex会导致程序终止,而recursive_mutex则不会,这个mutex允许同一线程多次锁定。

recursive_mutex g_mutex;
void print123()
{
	g_mutex.lock();
	g_mutex.lock();
	for (int i = 0; i < 3; i++) {
		this_thread::sleep_for(chrono::milliseconds(100));
		cout << i + 1;
	}
	g_mutex.unlock();
	g_mutex.unlock();
}

有时候线程想要锁定mutex,但又不想其它线程已锁定mutex时阻塞,这种情况下可以使用try_lock,它试图锁定mutex,成功就返回true,失败返回false。

为了等待特定长度的时间,你可以使用timed_mutex或recursive_timed_mutex的try_lock_for或try_lock_until方法。

由于try_lock在返回true时会锁定mutex,为了防止lock_guard重复锁定,需要传递参数adopt_lock。

void print123() 
{
	if (g_mutex.try_lock()) {
		lock_guard<mutex>  lockGuard(g_mutex,adopt_lock);
		for (int i = 0; i < 3; i++) {
			this_thread::sleep_for(chrono::milliseconds(100));
			cout << i + 1;
		}
	} else {
		cout << "mutex locked" <<endl;
	}
}
 
int main()
{
	thread(print123).detach();
	thread(print123).detach();
	system("pause");
}

通常一个线程一次只锁定一个mutex,然而有时候必须锁定多个mutex,如果一个个锁定,有可能出现锁定了第一个mutex,而无法锁定第二个mutex的情况。这种情况下可以使用全局函数lock锁定多个mutex。

mutex g_mutex1;
mutex g_mutex2;

void print123() 
{
	lock(g_mutex1, g_mutex2);
	lock_guard<mutex> lockGuard1(g_mutex1, adopt_lock);
	lock_guard<mutex> lockGuard2(g_mutex2, adopt_lock);
	for (int i = 0; i < 3; i++) {
		this_thread::sleep_for(chrono::milliseconds(100));
		cout << i + 1;
	}
}
 
int main()
{
	thread(print123).detach();
	thread(print123).detach();
	system("pause");
}

使用全局函数try_lock尝试锁定多个mutex,如果锁定所有mutex则返回-1,否则返回第一个失败的mutex的索引(从0开始),并且所有被成功lock的mutex会又被unlock。

mutex g_mutex1;
mutex g_mutex2;

void print123() 
{
	lock(g_mutex1, g_mutex2);
	lock_guard<mutex> lockGuard1(g_mutex1, adopt_lock);
	lock_guard<mutex> lockGuard2(g_mutex2, adopt_lock);
	for (int i = 0; i < 3; i++) {
		this_thread::sleep_for(chrono::milliseconds(100));
		cout << i + 1;
	}
}

void printLockState()
{
	auto result = try_lock(g_mutex1, g_mutex2);
	cout << result << endl;
	if (result == -1) {
		lock_guard<mutex> lockGuard1(g_mutex1, adopt_lock);
		lock_guard<mutex> lockGuard2(g_mutex2, adopt_lock);
	}
}
 
int main()
{
	thread(print123).detach();
	thread(printLockState).detach();
	system("pause");
}

 除了lock_guard,C++还提供一个类似的类unique_lock,它比lock_guard更灵活,unique_lock允许你明确指定何时锁定或解锁mutex,而lock_guard总是锁定mutex,如果unique_lock析构时mutex仍被锁住,析构函数会自动调用unlock,如果没有则不做任何事。

mutex g_mutex1;
timed_mutex g_mutex2;
 
int main()
{
	//尝试锁定mutex,但不会阻塞
	unique_lock<mutex> uniqueLock1(g_mutex1, try_to_lock);
	//尝试锁定mutex,不超过10秒
	unique_lock<timed_mutex> uniqueLock2(g_mutex2, chrono::seconds(10));
	//主动调用lock,try_lock,try_lock_for等才会锁定
	unique_lock<mutex> uniqueLock3(g_mutex1, defer_lock);
	//通过已锁定的mutex初始化
	unique_lock<mutex> uniqueLock4(g_mutex1, adopt_lock);
	//判断有没有锁定mutex
	cout << (uniqueLock1 ? "locked" : "unlocked")<< endl;
	cout << uniqueLock1.owns_lock() << endl;
	//解锁mutex
	uniqueLock1.unlock();
	//锁定mutex
	uniqueLock3.lock();
	system("pause");
}

 转载自:https://blog.csdn.net/xiongya8888/article/details/100399151

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值