卓姆比尼人免安装绿色版
637M · 2025-09-26
在 C++ 中,锁 是用于多线程编程的同步机制,用于保护共享资源,避免数据竞争和并发访问导致的问题。
C++ 标准库提供了多种锁的实现,包括互斥锁、读写锁、条件变量等。
在多线程环境中,多个线程可能同时访问或修改共享资源(如全局变量、数据结构等)。如果没有同步机制,可能会导致以下问题:
线程锁通过确保同一时间只有一个线程可以访问共享资源来解决这些问题。
mutex
, lock_guard
, condition_variable
)try_lock_for
)scoped_lock
和 shared_mutex
std::counting_semaphore
) 和原子智能指针互斥锁是最常用的锁类型,用于确保同一时间只有一个线程可以访问共享资源。
std::mutex
,基本的互斥锁。使用 lock()
和 unlock()
手动管理锁。使用 std::lock_guard
或 std::unique_lock
自动管理锁。
示例:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 全局互斥量
int sharedData = 0;
void increment() {
for (int i = 0; i < 1000; ++i) {
mtx.lock(); // 加锁
++sharedData;
mtx.unlock(); // 解锁
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Shared Data: " << sharedData << std::endl; // 输出: Shared Data: 2000
return 0;
}
自动管理锁的生命周期,离开作用域时自动释放锁。适用于简单的加锁场景。
std::lock_guard
会调用 std::mutex
的 lock()
方法,锁定互斥锁。如果互斥锁已被其他线程锁定,当前线程会阻塞,直到锁可用。std::lock_guard
会调用 std::mutex
的 unlock()
方法,释放互斥锁。即使发生异常,析构函数也会被调用,确保锁一定会被释放。std::lock_guard
是不可复制的,因为复制会导致多个对象管理同一个锁,从而引发未定义行为。#include <iostream>
#include <mutex>
#include <thread>
std::mutex mtx; // 全局互斥锁
int shared_data = 0; // 共享数据
void increment() {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁
++shared_data; // 操作共享数据
// 离开作用域时自动解锁
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Shared data: " << shared_data << std::endl; // 输出 2
return 0;
}
std::lock_guard
的生命周期受限于作用域,无法手动控制锁的释放。std::lock_guard
是不可移动的,无法转移锁的所有权。std::unique_lock
是一个功能强大的工具,提供了比 std::lock_guard
更多的灵活性和控制选项。它适用于需要手动控制锁、延迟加锁、锁的所有权转移或与条件变量配合使用的场景。在简单场景中,std::lock_guard
是更轻量级的选择;而在复杂场景中,std::unique_lock
是更合适的选择。
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
if(lock.try_lock()) {
// 操作...
lock.unlock(); // 手动解锁
}
lock()
)和解锁(unlock()
)。defer_lock
),在构造时不立即加锁。std::unique_lock
对象转移到另一个。std::condition_variable
配合使用,支持条件变量的等待操作。std::unique_lock<std::mutex> lock(mtx); // 立即加锁
std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟加锁
unlock()
释放锁。确保锁一定会被释放,即使发生异常。lock()
和 unlock()
方法,允许手动控制锁的状态。例如:
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
lock.lock(); // 手动加锁
lock.unlock(); // 手动解锁
std::unique_lock<std::mutex> lock1(mtx);
std::unique_lock<std::mutex> lock2 = std::move(lock1); // 所有权转移
std::condition_variable
配合使用,支持等待操作。例如:
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待条件变量
示例:
void increment() {
for (int i = 0; i < 1000; ++i) {
std::unique_lock<std::mutex> lock(mtx); // 自动加锁和解锁
++sharedData;
lock.unlock(); // 手动解锁
}
}
std::unique_lock
与 std::lock_guard
的区别
特性 | std::lock_guard | std::unique_lock |
---|---|---|
加锁策略 | 立即加锁 | 支持立即加锁、延迟加锁、尝试加锁 |
手动控制 | 不支持 | 支持手动加锁和解锁 |
所有权转移 | 不支持 | 支持移动语义,允许所有权转移 |
条件变量支持 | 不支持 | 支持与 std::condition_variable 配合 |
性能 | 更轻量,性能更高 | 更灵活,但性能稍低 |
std::recursive_mutex
是 C++ 标准库中的一种互斥锁类型,允许同一线程多次加锁而不会导致死锁。它适用于需要递归加锁的场景,例如在递归函数或嵌套调用中。
std::recursive_mutex
内部维护一个锁计数和一个线程 ID。std::mutex
的区别:
std::mutex
不允许同一线程多次加锁,否则会导致未定义行为或死锁。std::recursive_mutex
允许同一线程多次加锁,适用于递归或嵌套加锁的场景。以下是一个简单的 std::recursive_mutex
使用示例:
#include <iostream>
#include <thread>
#include <mutex>
std::recursive_mutex mtx; // 递归互斥锁
void recursive_function(int n) {
std::lock_guard<std::recursive_mutex> lock(mtx); // 加锁
if (n > 0) {
std::cout << "Thread " << std::this_thread::get_id() << ": n = " << n << std::endl;
recursive_function(n - 1); // 递归调用
}
// 离开作用域时自动解锁
}
int main() {
std::thread t1(recursive_function, 3);
std::thread t2(recursive_function, 2);
t1.join();
t2.join();
return 0;
}
输出示例:
Thread 140735680944896: n = 3
Thread 140735680944896: n = 2
Thread 140735680944896: n = 1
Thread 140735672552192: n = 2
Thread 140735672552192: n = 1
std::timed_mutex
是一种支持超时加锁的互斥锁,提供了 try_lock_for()
和 try_lock_until()
方法。
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::timed_mutex tmtx;
void tryLockFunction() {
if (tmtx.try_lock_for(std::chrono::milliseconds(100))) { // 尝试加锁,最多等待 100ms
std::cout << "Lock acquired!" << std::endl;
tmtx.unlock();
} else {
std::cout << "Failed to acquire lock!" << std::endl;
}
}
int main() {
std::thread t1(tryLockFunction);
std::thread t2(tryLockFunction);
t1.join();
t2.join();
return 0;
}
读写锁允许多个线程同时读取共享资源,但写操作需要独占访问。
C++17 引入的读写锁。
lock_shared()
和 unlock_shared()
进行读锁定。lock()
和 unlock()
进行写锁定。示例:
#include <iostream>
#include <thread>
#include <shared_mutex>
std::shared_mutex rwMutex;
int sharedData = 0;
void readData() {
std::shared_lock<std::shared_mutex> lock(rwMutex); // 读锁定
std::cout << "Read Data: " << sharedData << std::endl;
}
void writeData() {
std::unique_lock<std::shared_mutex> lock(rwMutex); // 写锁定
++sharedData;
std::cout << "Write Data: " << sharedData << std::endl;
}
int main() {
std::thread t1(readData);
std::thread t2(writeData);
t1.join();
t2.join();
return 0;
}
条件变量用于线程间的同步,允许线程等待某个条件成立。
std::mutex
配合使用。wait()
等待条件,notify_one()
或 notify_all()
通知等待的线程。核心方法
wait(lock); // 等待条件
wait(lock, predicate); // 带条件谓词的等待
notify_one(); // 通知一个等待线程
notify_all(); // 通知所有等待线程
示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void waitForReady() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; }); // 等待条件成立
std::cout << "Ready!" << std::endl;
}
void setReady() {
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one(); // 通知等待的线程
}
int main() {
std::thread t1(waitForReady);
std::thread t2(setReady);
t1.join();
t2.join();
return 0;
}
死锁是指多个线程互相等待对方释放锁,导致程序无法继续执行。
std::mutex mtx1, mtx2;
void thread1() {
mtx1.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mtx2.lock(); // 等待 mtx2
mtx2.unlock();
mtx1.unlock();
}
void thread2() {
mtx2.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
mtx1.lock(); // 等待 mtx1
mtx1.unlock();
mtx2.unlock();
}
int main() {
std::thread t1(thread1);
std::thread t2(thread2);
t1.join();
t2.join();
return 0;
}
std::lock()
同时锁定多个互斥锁。示例:
void thread1() {
std::lock(mtx1, mtx2); // 同时锁定
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
// 操作共享资源
}
void thread2() {
std::lock(mtx1, mtx2); // 同时锁定
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
// 操作共享资源
}
腾讯 QQ 音乐推出“网赚畅听包”会员,付费后每天看广告获取听歌权益
开源电子书管家 Calibre 8.11 发布:整合 AI 问答功能,随时解答你的提问