Bootstrap

std::lock_guard<std::mutex> 与 std::unique_lock<std::mutex> 的区别

  std::lock_guard 和 std::unique_lock 都是 C++11 中提供的用于互斥锁管理的工具,它们在许多方面是相似的,但也存在一些关键的区别:

std::lock_guard

  1. 自动管理std::lock_guard 是一个作用域锁(scoped lock),它会在构造时自动锁定互斥量,并在析构时自动解锁。因此,它是一种简单、安全的互斥量管理方式,可以防止忘记解锁。

  2. 不可转移std::lock_guard 不支持所有权转移,即你不能将一个 std::lock_guard 对象传递给另一个 std::lock_guard 对象。

  3. 不可解锁:一旦 std::lock_guard 锁定了互斥量,就不能再解锁它,直到 std::lock_guard 对象被销毁。

  4. 性能:由于 std::lock_guard 功能较为简单,因此它的性能开销通常比 std::unique_lock 小。

std::unique_lock

  1. 灵活管理std::unique_lock 提供了更多的灵活性。它可以手动锁定和解锁互斥量,还可以在构造时选择是否立即锁定。

  2. 可转移std::unique_lock 支持所有权转移,可以通过 std::move 操作将锁的所有权从一个 std::unique_lock 对象转移到另一个。

  3. 可解锁std::unique_lock 可以随时解锁和重新锁定互斥量。

  4. 条件变量std::unique_lock 可以与 std::condition_variable 一起使用,而 std::lock_guard 不可以。

  5. 性能:由于 std::unique_lock 提供了更多的功能,它的性能开销可能会比 std::lock_guard 大。

示例比较

下面是一个简单的例子,展示 std::lock_guard 和 std::unique_lock 的用法:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;

void print_with_lock_guard() {
    std::lock_guard<std::mutex> lg(mtx);
    std::cout << "Printing with lock_guard..." << std::endl;
    // mtx.unlock(); // 错误:不能手动解锁
}

void print_with_unique_lock() {
    std::unique_lock<std::mutex> ul(mtx);
    std::cout << "Printing with unique_lock..." << std::endl;
    ul.unlock(); // 可以手动解锁
    // Do some other work without holding the lock
    ul.lock(); // 可以手动锁定
    std::cout << "Locking again with unique_lock..." << std::endl;
}

int main() {
    std::thread t1(print_with_lock_guard);
    std::thread t2(print_with_unique_lock);

    t1.join();
    t2.join();

    return 0;
}

在大多数情况下,如果不需要 std::unique_lock 提供的额外灵活性,建议使用 std::lock_guard,因为它更简单且易于使用。如果需要更高级的锁定控制,比如需要在锁定和解锁之间执行其他操作,或者需要与条件变量一起使用,那么 std::unique_lock 是更好的选择。

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;