一 unique_lock取代lock_guard
unique_lock是个类模板,工作中,一般使用lock_guard。因为unqiue_lock占用的内存更多,效率底一些。但是unique_lock更加灵活,它的构造函数的第二个参数可以有其它的形式,下面会提到。同时,uniuqe_lock与lock_guard一样自动对绑定的互斥量自动加锁,解锁。
二 unique_lock的构造函数
-
std::adopt_lock
表示被绑定的互斥量已经被lock(),同lock_guard中一样。假设mutex已经lock成功了,再来使用。 -
std::try_to_lock
尝试使用mutex.lock()去锁住保护数据,如果没有锁成功,也会立即返回。流程不会阻塞,会继续进行下去。用std::try_to_lock的前提是你不能将mutex先锁住。示例:
// 把收到的消息传入队列
void inMsgRecvQueue()
{
for (size_t i = 0; i < 1000; ++i)
{
cout << "收到消息,并放入队列 " << i << endl;
unique_lock<mutex> my_uniq(my_mutex, std::try_to_lock); //在另一线程等待时,这个线程不会阻塞,等待mutex加锁。
if (my_uniq.owns_lock()) // 判断是否获得锁
{
msgRecvQueue.push_back(i);
}
else
{
cout << i << "入队时没有获得锁" << endl;
}
}
cout << "消息入队结束" << endl;
}
// 从队列中取出消息
void outMsgRecvQueue()
{
for (size_t i = 0; i < 1000; ++i)
{
unique_lock<mutex> my_uniq(my_mutex);
std::chrono::milliseconds dura(2 * 1000); // 2秒
std::this_thread::sleep_for(dura); // 等待2秒
if (!msgRecvQueue.empty())
{
// 队列不为空
int num = msgRecvQueue.front();
cout << "从消息队列中取出 " << num << endl;
msgRecvQueue.pop_front();
}
else
{
// 消息队列为空
cout << "消息队列为空 " << endl;
}
}
cout << "消息出队结束" << endl;
}
-
std::defer_lock
使用std::defer_lock的前提和std::try_to_lock一样,你不能提前对mutex lock()。它的意思是,初始化了一个没有加锁的mutex。通过这个参数,可以调用unique_lock的成员函数,来提前程序的灵活性,让锁的粒度越细。
那 … 什么是锁的粒度?
锁的粒度:有人把锁头锁住的代码的多少,叫作锁的粒度。粒度用粗细来描述。
锁住的代码量越少,粒度就越细,但是可能保护数据的安全。选择一个合适的粒度是高级程序员实力的体现。
举例:
unique_lock<mutex> my_uniq(my_mutex, std::defer_lock);
my_uniq.lock(); // 加锁
// 处理共享数据....
my_uniq.unlock();
// 处理非共享数据....
my_uniq.lock();
// 再处理共享数据....
三 unique_lock的成员函数
-
lock()
对mutex加锁 -
unlock()
对mutex解锁 -
try_lock()
与std::defer_lock一起使用,作用同std::try_to_lock一样,一直尝试会获得锁,如果没有获得,则返回false。示例:
// 把收到的消息传入队列
void inMsgRecvQueue()
{
for (size_t i = 0; i < 10000; ++i)
{
cout << "收到消息,并放入队列 " << i << endl;
unique_lock<mutex> my_uniq(my_mutex, std::defer_lock);
if (my_uniq.try_lock() == true) //如果取到锁
{
msgRecvQueue.push_back(i);
}
else
{
cout << i << "入队没有取得锁" << endl;
}
}
cout << "消息入队结束" << endl;
}
-
release()
返回它所管理的mutex对象指针,并释放所有权,也就是说,unique_lock与mutex不再有联系。如果之前mutex已经加锁,则要记得unlock()。示例:
// 从队列中取出消息
void outMsgRecvQueue()
{
for (size_t i = 0; i < 10000; ++i)
{
unique_lock<mutex> my_uniq(my_mutex);
std::mutex *ptx = my_uniq.release(); // 解除了mutex,要自己负责mutex的unlock()
if (!msgRecvQueue.empty())
{
// 队列不为空
int num = msgRecvQueue.front();
cout << "从消息队列中取出 " << num << endl;
msgRecvQueue.pop_front();
}
else
{
// 消息队列为空
cout << "消息队列为空 " << endl;
}
ptx->unlock(); // 这一步不能忘记
}
cout << "消息出队结束" << endl;
}
四 unique_lock的所有权转移
unique_lock所有权:unique_lock对象可以将绑定的mutex转交给其它unique_lock对象。
有两种方式:1 ,同unique_ptr一样,通过移动构造函数(不能通过拷贝构造函数)拷贝
unique_lock<mutex> my_uniq1(my_mutex);
unique_lock<mutex> my_uniq2(std::move(my_uniq1));
2,将unique_lock作为函数返回值。
std::unique_lock<mutex> rtn_unique_lock()
{
std::unique_lock<std::mutex> tmp_uniq(my_mutex);
return tmp_uniq;
}
版权声明:本文为I_just_smile原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。