声明:本文内容生成自ChatGPT,目的是为方便大家了解学习作为引用到作者的其他文章中。
std::unique_lock
是 C++ 标准库中的一种灵活的锁管理类,提供了比 std::lock_guard
更多的功能和灵活性。它可以控制对互斥锁(std::mutex
)的独占所有权,并允许手动锁定、解锁、尝试锁定等操作。
与 std::lock_guard
不同,std::unique_lock
可以:
- 延迟锁定:允许在构造后再锁定互斥锁。
- 提前解锁:可以在作用域内的某个时刻手动解锁互斥锁。
- 尝试锁定 :可以使用
try_lock()
方法尝试锁定互斥锁。
语法
cpp
std::unique_lock<std::mutex> lock(mutex);
或
cpp
std::unique_lock<std::mutex> lock(mutex, std::defer_lock); // 延迟锁定
构造函数
std::unique_lock
的构造函数有几种常用形式:
-
立即锁定(默认行为):
std::unique_lock<std::mutex> lock(mutex);
- 创建
unique_lock
时会自动锁定传递的mutex
。
-
延迟锁定(不锁定互斥锁):
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
- 创建
unique_lock
时不会立即锁定互斥锁,你需要手动调用lock()
来锁定。
-
尝试锁定(尝试立即锁定):
std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
- 尝试锁定互斥锁,如果锁定失败,不会阻塞线程,可以通过
lock.owns_lock()
检查是否成功获得锁。
-
直接采用已有的锁定:
std::unique_lock<std::mutex> lock(mutex, std::adopt_lock);
- 使用此选项表明互斥锁已经被锁定,
unique_lock
不会再次尝试锁定。
std::unique_lock
常用方法
lock()
:手动锁定互斥锁。如果在构造时选择了std::defer_lock
,你可以使用lock()
方法来在稍后锁定互斥锁。unlock()
:手动解锁互斥锁。你可以在需要时释放锁以允许其他线程访问共享资源。try_lock()
:尝试锁定互斥锁。如果锁定成功,返回true
,否则返回false
。该方法不会阻塞线程。owns_lock()
:返回一个布尔值,表示unique_lock
是否拥有互斥锁的所有权。release()
:释放unique_lock
对互斥锁的控制权,但不会解锁互斥锁。这在某些高级场景中可能有用。
示例
1. 基本使用
cpp
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void printThreadId(int id) {
std::unique_lock<std::mutex> lock(mtx); // 自动锁定互斥锁
std::cout << "Thread ID: " << id << std::endl;
// lock 作用域结束后自动解锁
}
int main() {
std::thread t1(printThreadId, 1);
std::thread t2(printThreadId, 2);
t1.join();
t2.join();
return 0;
}
2. 延迟锁定
cpp
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void work() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟锁定
std::cout << "Before locking." << std::endl;
lock.lock(); // 手动锁定
std::cout << "Lock acquired." << std::endl;
lock.unlock(); // 手动解锁
std::cout << "Lock released." << std::endl;
}
int main() {
std::thread t1(work);
std::thread t2(work);
t1.join();
t2.join();
return 0;
}
在这个例子中,互斥锁在稍后通过 lock()
手动锁定,然后通过 unlock()
解锁。
3. 尝试锁定
cpp
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void tryLockWork() {
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
if (lock.owns_lock()) {
std::cout << "Lock acquired by thread." << std::endl;
} else {
std::cout << "Failed to acquire lock." << std::endl;
}
}
int main() {
std::thread t1(tryLockWork);
std::thread t2(tryLockWork);
t1.join();
t2.join();
return 0;
}
在这个例子中,我们使用 std::try_to_lock
尝试获取锁。如果某个线程在尝试锁定时已经锁定了互斥锁,另一个线程将无法获得锁并输出"Failed to acquire lock"。
std::unique_lock
与 std::lock_guard
的区别
- 灵活性 :
std::unique_lock
提供了更多的功能(如延迟锁定、手动解锁和尝试锁定),而std::lock_guard
则是一个更加轻量级的加锁工具,自动加锁并在作用域结束时解锁。 - 性能 :
std::lock_guard
比std::unique_lock
更高效,因为它是针对简单的加锁/解锁场景设计的,没有额外的操作开销。如果你只需要在构造和析构时加锁和解锁,使用std::lock_guard
更加合适。 - 场景 :当你需要在代码的某些部分手动解锁或延迟加锁时,
std::unique_lock
是更好的选择。如果你只需要简单的加锁和解锁,std::lock_guard
就足够了。
总结
std::unique_lock
提供了一个灵活的互斥锁管理工具,支持延迟锁定、手动解锁和尝试锁定等高级功能。- 与
std::lock_guard
相比,std::unique_lock
在锁管理方面有更多的控制权,适用于更复杂的同步场景。 - 在多线程编程中,
std::unique_lock
适合那些需要在特定时刻手动锁定或解锁的场景,而std::lock_guard
则更适合简单、固定的锁管理。