当前位置: 首页 > news >正文

C++中unique_lock和lock_guard区别

目录

1.自动锁定与解锁机制

2.灵活性

3.所有权转移

4.可与条件变量配合使用

5.性能开销


在 C++ 中,std::unique_lock 和 std::lock_guard 都属于标准库 <mutex> 中的互斥锁管理工具,用于简化互斥锁的使用并确保线程安全。但它们存在一些显著区别,下面为你详细介绍:

1.自动锁定与解锁机制

1) std::lock_guard:一个轻量级的互斥锁包装器,采用了 RAII(资源获取即初始化)技术。当 std::lock_guard 对象被创建时,它会自动锁定所关联的互斥锁;当对象离开其作用域时,会自动解锁该互斥锁。它的设计遵循最小化原则,仅提供最基本的锁管理功能,没有额外的开销。其核心实现原理可以简化为:

template<classMutex>
classlock_guard {
public:explicitlock_guard(Mutex& m) : mutex(m) {mutex.lock();}~lock_guard() {mutex.unlock();}lock_guard(const lock_guard&) = delete;lock_guard& operator=(const lock_guard&) = delete;private:Mutex& mutex;
};

        示例代码如下:

#include <iostream>
#include <mutex>
#include <thread>std::mutex mtx;void printMessage() {std::lock_guard<std::mutex> lock(mtx);std::cout << "This message is protected by lock_guard." << std::endl;// 当 lock_guard 对象离开作用域时,互斥锁会自动解锁
}int main() {std::thread t(printMessage);t.join();return 0;
}

2) std::unique_lock: 同样基于 RAII 技术,在对象销毁时会自动解锁互斥锁。不过,它的锁定和解锁操作更加灵活,可以在对象创建时选择不立即锁定互斥锁,也可以在对象生命周期内手动锁定和解锁。unique_lock 是 C++11 标准中引入的更高级的锁管理器,设计目标是提供更灵活的锁管理能力。其核心接口包括:

class unique_lock {
public:// 构造时可选立即加锁、延迟加锁或尝试加锁unique_lock(mutex_type& m, std::defer_lock_t) noexcept;unique_lock(mutex_type& m, std::try_to_lock_t);unique_lock(mutex_type& m, std::adopt_lock_t);// 转移构造函数unique_lock(unique_lock&& other) noexcept;// 手动控制接口voidlock();booltry_lock();voidunlock();// 状态查询explicitoperatorbool()constnoexcept;boolowns_lock()constnoexcept;
};

            示例代码如下:

    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void printMessage() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 手动锁定互斥锁lock.lock();std::cout << "This message is protected by unique_lock." << std::endl;// 手动解锁互斥锁lock.unlock();
    }int main() {std::thread t(printMessage);t.join();return 0;
    }

    std::unique_lock 允许在对象生命周期内多次手动调用 lock()unlock() 和 try_lock() 方法。这在需要在临界区内进行部分操作后暂时释放锁,执行一些非关键操作,然后再次锁定的场景中很有用。如:

    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx);std::cout << "Entered critical section." << std::endl;// 执行部分临界区操作lock.unlock();std::cout << "Temporarily released the lock." << std::endl;// 执行一些非关键操作lock.lock();std::cout << "Re - entered critical section." << std::endl;// 继续执行临界区操作
    }int main() {std::thread t(work);t.join();return 0;
    }

    2.灵活性

    1)std::lock_guard: 功能相对单一,缺乏灵活性。一旦创建,就会立即锁定互斥锁,并且在其生命周期内无法手动解锁,只能在对象离开作用域时自动解锁。

    2)std::unique_lock:具有更高的灵活性。它支持三种锁定策略:

    std::defer_lock_t   // 延迟锁定
    std::try_to_lock_t  // 尝试锁定
    std::adopt_lock_t   // 接管已锁定状态
    • 延迟锁定(std::defer_lock:创建 std::unique_lock 对象时,可以选择不立即锁定互斥锁。这在需要先进行一些准备工作,之后再锁定互斥锁的场景中非常有用。如:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx, std::defer_lock);// 进行一些无需加锁的准备工作std::cout << "Doing some preparation work..." << std::endl;lock.lock();std::cout << "Critical section entered." << std::endl;// 临界区代码lock.unlock();std::cout << "Critical section exited." << std::endl;
    }int main() {std::thread t(work);t.join();return 0;
    }
    • 尝试锁定(std::try_to_lock:使用 std::try_to_lock 可以尝试锁定互斥锁,如果互斥锁当前已被其他线程锁定,std::unique_lock 对象不会阻塞,而是立即返回,可通过 owns_lock() 方法判断是否成功锁定。如:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;void work() {std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);if (lock.owns_lock()) {std::cout << "Successfully locked the mutex." << std::endl;// 临界区代码} else {std::cout << "Failed to lock the mutex, doing other work." << std::endl;// 执行其他不需要锁定互斥锁的工作}
    }int main() {std::thread t(work);t.join();return 0;
    }

    3.所有权转移

    • std::lock_guard
      • 不支持所有权转移,即不能将一个 std::lock_guard 对象的互斥锁所有权转移给另一个对象。
    • std::unique_lock
      • 支持所有权转移,可以通过移动构造函数或移动赋值运算符将互斥锁的所有权从一个 std::unique_lock 对象转移到另一个对象。这在函数返回 std::unique_lock 对象或需要在不同作用域之间传递锁的所有权时非常有用。
      • 示例代码如下:
    #include <iostream>
    #include <mutex>
    #include <thread>std::mutex mtx;std::unique_lock<std::mutex> getLock() {std::unique_lock<std::mutex> lock(mtx);return std::move(lock);
    }void printMessage() {std::unique_lock<std::mutex> lock = getLock();std::cout << "This message is protected by transferred unique_lock." << std::endl;
    }int main() {std::thread t(printMessage);t.join();return 0;
    }

    4.可与条件变量配合使用

    std::unique_lock 能够与 std::condition_variable 一起使用,std::condition_variable 的 wait()wait_for() 和 wait_until() 等方法要求传入 std::unique_lock 对象,因为在等待期间需要释放和重新获取锁。

    #include <iostream>
    #include <mutex>
    #include <condition_variable>
    #include <thread>std::mutex mtx;
    std::condition_variable cv;
    bool ready = false;void worker() {std::unique_lock<std::mutex> lock(mtx);cv.wait(lock, []{ return ready; });std::cout << "Worker thread is working." << std::endl;
    }int main() {std::thread t(worker);{std::lock_guard<std::mutex> lock(mtx);ready = true;}cv.notify_one();t.join();return 0;
    }

    5.性能开销

    • std::lock_guard
      • 由于其功能简单,没有额外的状态管理,因此性能开销相对较小,适合用于简单的锁定场景。
    • std::unique_lock
      • 为了支持更多的灵活性,std::unique_lock 需要维护更多的状态信息,因此性能开销相对较大。在对性能要求极高且锁定逻辑简单的场景下,使用 std::lock_guard 更为合适。

    综上所述,std::lock_guard 适用于简单的锁定场景,追求简洁性和较低的性能开销;而 std::unique_lock 则适用于需要更复杂锁定逻辑、支持所有权转移的场景,但会带来一定的性能开销。

    推荐阅读

    深入理解C++中的锁

    C++惯用法之RAII思想: 资源管理

    Qt之条件变量QWaitCondition详解(从使用到原理分析全)

    相关文章:

  • T1结构像+RS-fMRI影像处理完整过程记录(数据下载+Matlab工具箱+数据处理)
  • 【第45节】windows程序的其他反调试手段上篇
  • 【2025年3月中科院1区SCI】Rating entropy等级熵及5种多尺度,特征提取、故障诊断新方法!
  • Docker技术基础新手入门教程
  • 获取类路径
  • NLP高频面试题(四十二)——RAG系统评估:方法、指标与实践指南
  • bash的特性-常用的通配符
  • HarmonyOS-ArkUI V2装饰器: @Computed装饰器:计算属性
  • 【刷题2025】知识点梳理
  • Notepad++中将文档格式从Windows(CR LF)转换为Unix(LF)
  • ollama修改配置使用多GPU,使用EvalScope进行模型压力测试,查看使用负载均衡前后的性能区别
  • vue复习46~90
  • designware IP如何被FPGA综合
  • 【控制学】控制学分类
  • 儿童后期至青少年早期脑网络隔离增强的发育机制研究
  • 中国反制关税影响分析、可能性分析
  • 基于Python的PC控制Robot 小程序开发历程
  • 虚拟机ubuntu网络如何使用windows物理机的代理
  • 【差分隐私相关概念】瑞丽差分隐私(RDP)引理1
  • 【差分隐私相关概念】瑞丽差分隐私(RDP)-命题1
  • 两部门发布“五一”假期全国森林草原火险形势预测
  • 学有质量、查有力度、改有成效,广大党员干部落实中央八项规定精神
  • 西夏文残碑等文物来沪,见证一段神秘灿烂的历史
  • 坚守刑事检察一线13年,“在我心中每次庭审都是一次大考”
  • 大学2025丨专访北邮校长徐坤:工科教育要真正回归工程本质
  • 铜钴巨头洛阳钼业一季度净利润同比大增九成,最新宣布首度进军黄金矿产