C++日记——Day41:unique_lock详解

unique_lock取代lock_guard

unique是个类模板,工作中,一般lock_guard(推荐使用);

lock_guard取代了mutex的 lock() 和 unlock();

unique_lock比lock_guard灵活很多,效率上差一些,内存占用多一些

#include <thread>
#include <iostream>
#include <list>
#include <mutex>
using namespace std;

class A {
public:
	void inMsgRecvQueue() {
		for (int i = 0; i < 10000; ++i) {
			cout << "inMsgRecvQueue插入一个元素" << i << endl;
			std::lock(mymutex1, mymutex2);
			std::unique_lock<std::mutex> sbguard1(mymutex1, std::adopt_lock);
			//std::lock_guard<std::mutex> sbguard2(mymutex2, std::adopt_lock);
			msgRecvQueue.push_back(i);
			//mymutex2.unlock();
			//...其他操作
			//mymutex1.unlock();
		}
	}

	bool outMsgProc(int &command) {
		std::lock(mymutex1, mymutex2);
		std::unique_lock<std::mutex> sbguard1(mymutex1, std::adopt_lock);
		//std::lock_guard<std::mutex> sbguard2(mymutex2, std::adopt_lock);
		if (!msgRecvQueue.empty()) {
			command = msgRecvQueue.front();
			msgRecvQueue.pop_front();
			//mymutex1.unlock();
			//mymutex2.unlock();
			return true;
		}
		//mymutex1.unlock();
		//mymutex2.unlock();
		return false;
	}

	void outMsgRecvQueue() {
		int command = 0;
		for (int i = 0; i < 10000; ++i) {
			bool re = outMsgProc(command);
			if (re == true) {
				cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
			}
			else {
				cout << "消息队列为空" << endl;
			}
		}
	}

private:
	std::list<int> msgRecvQueue;
	std::mutex mymutex1;
	std::mutex mymutex2;
};

int main() {
	A myobja;
	std::thread myoutobj(&A::outMsgRecvQueue, &myobja); //注意这里myobja用引用,才能保证线程里用的是同一个对象
	std::thread myinobj(&A::inMsgRecvQueue, &myobja);
	myinobj.join();
	myoutobj.join();
}

 

unique_lock可以带第二个参数

1、std::adopt_lock:表示互斥量已经被lock了(程序员必须把互斥量先lock,否则会报异常)

效果:假设线程调用方赢拥有了互斥的所有权

lock_graud与unique_lock都可以加这个参数,意义相同。

2、std::try_to_lock

我们会尝试用mutex中的lock()去锁定这个mutex,但如果没有锁定成功,也会立刻返回,并不会阻塞;

#include <thread>
#include <iostream>
#include <list>
#include <mutex>
using namespace std;

class A {
public:
	void inMsgRecvQueue() {
		for (int i = 0; i < 10000; ++i) {
			cout << "inMsgRecvQueue插入一个元素" << i << endl;
			
			std::unique_lock<std::mutex> sbguard1(mymutex1, std::try_to_lock);
			if (sbguard1.owns_lock()) {  //判断是否拿到了锁
				msgRecvQueue.push_back(i);  //拿到了锁
			}
			else {
				cout << "没能拿到锁" << endl;
			}
		}
	}

	bool outMsgProc(int &command) {
		mymutex1.lock();
		std::unique_lock<std::mutex> sbguard1(mymutex1, std::adopt_lock);
		//std::lock_guard<std::mutex> sbguard2(mymutex2, std::adopt_lock);

		std::chrono::milliseconds dura(20000);
		std::this_thread::sleep_for(dura);

		if (!msgRecvQueue.empty()) {
			command = msgRecvQueue.front();
			msgRecvQueue.pop_front();
			return true;
		}
		return false;
	}

	void outMsgRecvQueue() {
		int command = 0;
		for (int i = 0; i < 10000; ++i) {
			bool re = outMsgProc(command);
			if (re == true) {
				cout << "outMsgRecvQueue执行,取出一个元素" << command << endl;
			}
			else {
				cout << "消息队列为空" << endl;
			}
		}
	}

private:
	std::list<int> msgRecvQueue;
	std::mutex mymutex1;
};

int main() {
	A myobja;
	std::thread myoutobj(&A::outMsgRecvQueue, &myobja); //注意这里myobja用引用,才能保证线程里用的是同一个对象
	std::thread myinobj(&A::inMsgRecvQueue, &myobja);
	myinobj.join();
	myoutobj.join();
}

通过这种方式让线程在没有拿到锁时执行其他事情

3、std::defer_lock:前提是你不能先lock(),否则汇报异常

defer_lock的意思是并没有给mutex枷锁:初始化了一个没有加锁的mutex

我们借着defer_lock的话题来介绍一些unique_lock的重要成员函数

 

unique的成员函数(与defer_lock配合使用)

1、lock():加锁,加锁后,不用必须加unlock,unique_lock会帮助我们unlock()

2、unlock():解锁,如果想自己解锁,也可以使用unlock()

为什么需要unlock(),因为你锁住的代码段越少,执行越快,整个程序效率就越高。

也有人把搜头锁住的代码多少称为 粒度。一般用粗细描述。

a、锁住的代码少,粒度细;b、锁住的代码多粒度粗

3、try_lock():尝试给互斥量加锁,如果拿不到锁返回false,如果拿到了锁,返回true

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

如果原来mutex对象处于加锁状态

std::mutex mymutex1;

std::unique_lock<std::mutex> myuniquemutex(mymutex1);


std::mutex *pmutex = myuniquemutex.release();
//此时,你就需要自己unlock()了

 

unique_lock所有权传递

std::mutex mymutex1;
std::unique_lock<std::mutex> sbguard1(mymutex1);

此时,sbguard1拥有mymutex1的所有权,

std::unique_lock<std::mutex> sbguard2(sbguard1); //非法
std::unique_lock<std::mutex> sbguard2(std::move(sbguard1)); //移动语义,现在相当于sbguard2与mymutex1绑定到一起了
class Test{
public:
    std::mutex mymutex1;
    std::uniuqe_lock<std::mutex> rtn_guard(){
    
        std::unique_lock<std::mutex> tmpmutex(mymutex1);
        return tmpmutex; //因为tmpmutex为局部变量,函数返回局部变量时,会产生一个临 
                         //时对象,并调用移动构造函数传递给外部变量
    }
    std::uniuqe_lock<std::mutex> sbguard1 = rtn_guard();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值