是C++11标准库中用于多线程同步的库,提供互斥锁(mutex)及其相关函数。
以下是一些基本的使用示例:
1.创建和销毁互斥锁
#include <mutex>
std::mutex mtx;
2.加锁
std::lock_guard<std::mutex> lock(mtx); // 加锁
// 或者
mtx.lock(); // 加锁
3.解锁
mtx.unlock(); // 解锁
4.尝试加锁
if(mtx.try_lock()) {
// 成功加锁
} else {
// 加锁失败
}
5.在条件变量中使用互斥锁
条件变量(<condition_variable>)常常与互斥锁一起使用,用于等待某个条件成立。
#include <condition_variable>
#include <mutex>
#include <thread>
#include <chrono>
#include <iostream>
std::mutex mtx; // 全局互斥锁.
std::condition_variable cv; // 全局条件变量.
bool ready = false; // 全局状态变量.
void print_id(int id)
{
std::unique_lock<std::mutex> lock(mtx); // 加锁.
while (!ready)
{ // 如果还没就绪就等待...
cv.wait(lock); // 在此锁上等待条件变量的通知.
} // 继续执行...
std::cout << "thread " << id << '\n'; // 打印线程id.
} // 释放锁.
void go()
{ // 在主线程中调用这个函数来启动所有线程的运行.
std::unique_lock<std::mutex> lock(mtx); // 加锁.
ready = true; // 设置全局状态为就绪.
cv.notify_all(); // 通知所有在等待的线程.
} // 释放锁.
int main()
{ // 主线程函数.
std::thread threads[10]; // 创建10个线程的线程数组.
for (int i = 0; i < 10; ++i)
{ // 对每个线程进行以下操作:
threads[i] = std::thread(print_id, i); // 创建新线程并指定函数和参数.
} // 主线程继续执行其他操作...
std::cout << "10 threads ready to race...\n"; // 输出消息表明所有线程已准备好竞争运行.
go(); // 设置全局状态为就绪并通知所有等待的线程.
for (int i = 0; i < 10; ++i)
{
threads[i].join();
}
return 0;
}
注:
go()方法中如果有一个线程首先开始打印, 则其他线程会立即开始打印, 因为它们在cv上等待时被阻塞了,所以它们会立即得到cv的信号并退出等待状态. 所有线程都打印完后,会释放mtx并使cv通知其他线程的线程调度的线程调度函数中的任务完成. 这个函数就会立即返回,其他任务也就会立即执行, 这样它们就能抢在其他线程之前开始执行了, 因为它们已经在"起跑线"上了!这是一种非常常见的模式, 特别是在并发编程中, 当我们希望所有线程/进程尽快开始执行任务时.这种模式被称为"起跑信号". 在这种情况下, 如果有多个线程同时打印, 则它们的输出可能是交错的,因为它们是并发执行的, 所以它们的执行顺序是不确定的.
6.使用多个互斥锁
你可以使用多个互斥锁以实现更细粒度的同步。例如,你可能有一个用于保护访问共享资源的互斥锁,同时还有一个用于保护访问其他特定资源的互斥锁。
std::mutex mutex1;
std::mutex mutex2;
// 使用两个互斥锁
std::lock_guard<std::mutex> lock1(mutex1);
std::lock_guard<std::mutex> lock2(mutex2);
// 对共享资源进行操作
// ...
// 对其他特定资源进行操作
// ...
7.自定义互斥锁
C++11允许你实现自定义的互斥锁。这可能对于特殊情况下,标准库提供的互斥锁不适用的情况。自定义互斥锁可以让你更深入地控制线程同步的行为。
class CustomMutex {
public:
void lock() {
// 实现自定义加锁逻辑
}
void unlock() {
// 实现自定义解锁逻辑
}
};
// 使用自定义互斥锁
CustomMutex mutex;
std::lock_guard<CustomMutex> lock(mutex);
8.避免死锁
使用互斥锁时,要特别注意避免死锁。死锁是指两个或更多的线程相互等待对方释放资源,导致所有线程都无法继续执行的情况。你应该总是确保在可能的情况下按正确的顺序获取锁。
9.使用std::lock()来同时锁定多个互斥锁
C++11标准库提供了std::lock()函数,可以同时锁定多个互斥锁,以避免死锁。这个函数会以不确定的顺序锁定传入的互斥锁。这样,你可以一次性锁定所有需要的互斥锁,而不是逐个锁定,以增加代码的清晰性。
std::mutex mutex1;
std::mutex mutex2;
std::lock(mutex1, mutex2); // 同时锁定两个互斥锁