(C++11/14/17学习笔记):unique_lock
发布日期:2021-05-07 15:19:51 浏览次数:24 分类:精选文章

本文共 3347 字,大约阅读时间需要 11 分钟。

unique_lock深入解析

在C++多线程编程中,unique_lock是一个强大的互斥量管理工具,它不仅提供了灵活的锁管理选项,还支持多种参数和成员函数,能够满足不同场景下的复杂锁定需求。以下将从多个维度深入分析unique_lock的使用方法及其特点。

1. unique_lock的基本用法

unique_lock是一个类模板,主要用于管理互斥量(Mutex)。与lock_guard不同,unique_lock需要手动调用lock()unlock()方法,提供了更高的控制权。

1.1 构造函数参数

unique_lock的构造函数接受多个参数,其中包括std::adopt_lockstd::try_to_lockstd::defer_lock等。这些参数赋予了unique_lock高度的灵活性。

  • std::adopt_lock:表示unique_lock已经拥有了某个互斥量的所有权。这意味着在使用adopt_lock时,unique_lock不需要自己调用lock()方法,而是直接进行操作。

  • std::try_to_lock:这是一个非阻塞的锁获取方式。try_lock()尝试获取锁,如果未成功,会立即返回,避免线程被挂起。

  • std::defer_lock:表示unique_lock不会自动加锁,而是需要手动调用lock()方法。这对于需要自定义锁定逻辑的场景非常有用。

1.2 加锁与解锁

unique_lock的核心成员函数包括lock()unlock()

  • lock():手动加锁,确保只有一条线程能够执行后续代码。需要注意的是,在使用adopt_locktry_to_lock时,必须确保互斥量已经被正确加锁。

  • unlock():手动解锁,释放互斥量的所有权。这一步必须在unique_lock控制的锁定范围内完成,否则可能导致死锁或数据竞争。

2. unique_lock的高级功能

unique_lock支持多种高级功能,提升了多线程编程的效率和安全性。

2.1 统一锁管理

unique_lock可以通过release()方法获取原始互斥量指针,并释放所有权。这对于在多线程环境中管理多个互斥量非常有用,能够灵活地分配和管理锁的使用。

2.2 所有权传递

unique_lock支持所有权的传递,即可以将一个unique_lock对象的所有权转移给另一个unique_lock对象。这在资源管理方面非常灵活,但需要正确处理,以避免资源泄漏或竞态条件。

2.3 异步锁管理

在某些情况下,可以使用std::chrono::milliseconds设置超时,通过try_lock()方法尝试获取锁。如果在指定时间内未能获取锁,线程会继续执行其他任务,而不是无限等待。

3. 使用示例

以下是一个使用unique_lock的示例,展示了如何灵活地管理互斥量。

#include 
#include
#include
#include
#include
#include
#include
using namespace std;class A {public: void inMsgRecvQueue() { for (int i = 1; i < 10000; ++i) { cout << "inMsgRecvQueue执行了,插入一个元素" << i << endl; unique_lock
in_mutex_guard(my_mutex, std::adopt_lock); in_mutex_guard.lock(); msgRecvQueue.push_back(i); } } bool outMsgMutPro(int& command) { unique_lock
out_mutex_guard1(my_mutex, std::defer_lock); out_mutex_guard1.lock(); this_thread::sleep_for(chrono::milliseconds(2000)); if (!msgRecvQueue.empty()) { command = msgRecvQueue.front(); msgRecvQueue.pop_front(); return true; } return false; } void outMsgRecvQueue() { int command{}; for (int i = 1; i < 10000; ++i) { bool ret = outMsgMutPro(command); if (ret) { cout << "outMsgMutPro执行了,取出一个元素" << command << endl; } else { cout << "outMsgRecvQueue执行了,但是当前消息队列为空" << i << endl; } } cout << "outMsgRecvQueue()执行完毕" << endl; }private: list
msgRecvQueue; Mutex my_mutex;};int main() { A obja; thread outMsgThread(&A::outMsgRecvQueue, &obja); thread inMsgThread(&A::inMsgRecvQueue, &obja); inMsgThread.join(); outMsgThread.join(); cout << "主线程结束" << endl; return 0;}

3.1 使用adopt_lock

inMsgRecvQueue()函数中,使用adopt_lock参数,表示unique_lock已经拥有了my_mutex的所有权,无需再次加锁。

unique_lock
in_mutex_guard(my_mutex, std::adopt_lock);in_mutex_guard.lock();

3.2 使用try_to_lock

outMsgMutPro()函数中,使用try_to_lock方法,尝试在指定时间内获取锁。

unique_lock
out_mutex_guard1(my_mutex, std::try_to_lock);if (out_mutex_guard1.try_lock() == true) { // 代码执行} else { // 无法获取锁,继续执行}

3.3 使用defer_lock

unique_lock构造时使用defer_lock参数,表示不自动加锁,需要手动调用lock()

unique_lock
out_mutex_guard1(my_mutex, std::defer_lock);out_mutex_guard1.lock();

4. 注意事项

在使用unique_lock时,需要注意以下几点:

  • 确保所有权:在使用adopt_locktry_to_lock时,必须确保互斥量已经被正确加锁,否则会导致异常。

  • 正确解锁:手动调用unlock()时,必须确保解锁的正确性,避免死锁或数据竞争。

  • 资源管理:正确管理所有权和互斥量,防止资源泄漏或竞态条件。

  • 性能考虑:由于unique_lock的高层次控制,可能影响性能。在高并发场景下,需要权衡灵活性和效率。

  • 5. 总结

    unique_lock是一个强大的互斥量管理工具,提供了高度的灵活性和控制力。它支持多种参数和成员函数,能够满足不同场景下的复杂锁定需求。然而,其高层次控制也带来了更高的复杂性和潜在的错误风险。因此,在使用unique_lock时,开发者需要具备较强的多线程编程能力,正确管理锁的获取和释放,以确保程序的安全性和高效性。

    上一篇:(C++11/14/17学习笔记):单例设计模式共享数据分析,call_once()函数
    下一篇:(C++11/14/17学习笔记):互斥量概念、用法、死锁演示及解决详解

    发表评论

    最新留言

    做的很好,不错不错
    [***.243.131.199]2025年04月09日 05时00分15秒