关于互斥锁的理解

参考文档

  1. https://blog.youkuaiyun.com/google19890102/article/details/62047798
  2. https://blog.youkuaiyun.com/tennysonsky/article/details/46494077

互斥锁
互斥锁是通过锁的机制来实现线程间的同步问题。互斥锁的基本流程为:

初始化一个互斥锁:pthread_mutex_init() 函数
加锁:pthread_mutex_lock()函数或者pthread_mutex_trylock()函数
对共享资源的操作
解锁:pthread_mutex_unlock()函数
注销互斥锁:pthread_mutex_destory()函数

其中,在加锁过程中,pthread_mutex_lock()函数和pthread_mutex_trylock()函数的过程略有不同:
当使用pthread_mutex_lock()函数进行加锁时,若此时已经被锁,则尝试加锁的线程会被阻塞,直到互斥锁被其他线程释放,当pthread_mutex_lock()函数有返回值时,说明加锁成功;
而使用pthread_mutex_trylock()函数进行加锁时,若此时已经被锁,则会返回EBUSY的错误码。

同时,解锁的过程中,也需要满足两个条件:
解锁前,互斥锁必须处于锁定状态; 必须由加锁的线程进行解锁。

当互斥锁使用完成后,必须进行清除。

<think>我们即将讨论C++中的互斥锁(Mutex)。互斥锁是并发编程中用于保护共享资源不被多个线程同时访问的同步机制。在C++中,互斥锁主要通过`<mutex>`头文件提供。 我们将涵盖以下几个方面: 1. 基本互斥锁(std::mutex) 2. 锁守卫(std::lock_guard)和唯一锁(std::unique_lock) 3. 其他类型的互斥锁:递归互斥锁(std::recursive_mutex)、定时互斥锁(std::timed_mutex)等 4. 死锁预防(std::lock和std::try_lock) 5. 条件变量(std::condition_variable)与互斥锁的配合使用 下面我们通过代码示例来详细解释。 </think> # C++互斥锁(Mutex)详解 在C++中,互斥锁(mutex)是同步原语,用于保护共享资源不被多个线程同时访问,防止数据竞争(data race)。以下是C++互斥锁的全面解析和代码示例。 ## 1. 基本互斥锁(std::mutex) ```cpp #include <iostream> #include <thread> #include <mutex> std::mutex mtx; // 全局互斥锁 int shared_data = 0; // 共享资源 void increment(int n) { for (int i = 0; i < n; ++i) { mtx.lock(); // 获取锁 ++shared_data; // 临界区操作 mtx.unlock(); // 释放锁 } } int main() { const int iterations = 100000; std::thread t1(increment, iterations); std::thread t2(increment, iterations); t1.join(); t2.join(); std::cout << "最终值: " << shared_data << " (应为: " << 2 * iterations << ")\n"; return 0; } ``` **关键点**: - `lock()`: 阻塞直到获取锁 - `unlock()`: 释放锁 - 必须成对使用,否则可能导致死锁 - 不推荐直接使用,更推荐RAII包装器 ## 2. RAII包装器:lock_guard ```cpp void safe_increment(int n) { for (int i = 0; i < n; ++i) { std::lock_guard<std::mutex> lock(mtx); // 自动锁解锁 ++shared_data; // 离开作用域自动解锁 } } ``` **优势**: - 异常安全:即使发生异常也能保证解锁 - 避免忘记解锁 - 作用域结束自动释放 ## 3. 更灵活的unique_lock ```cpp void transfer(int amount, int& from, int& to) { std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock); std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock); // 避免死锁的锁方式 std::lock(lock1, lock2); // 原子性地获取多个锁 from -= amount; to += amount; // 自动解锁 } ``` **特性**: - 延迟锁定(`std::defer_lock`) - 转移所有权 - 手动锁定/解锁 - 支持条件变量 ## 4. 递归互斥锁(std::recursive_mutex) ```cpp std::recursive_mutex rec_mtx; void recursive_function(int depth) { std::lock_guard<std::recursive_mutex> lock(rec_mtx); if (depth > 0) { recursive_function(depth - 1); } } int main() { std::thread t(recursive_function, 3); t.join(); return 0; } ``` **适用场景**: - 递归函数需要多次锁 - 同一个线程需要多次获取同一锁 - 普通mutex会导致死锁的情况 ## 5. 定时互斥锁(std::timed_mutex) ```cpp std::timed_mutex timed_mtx; void timed_access() { auto timeout = std::chrono::milliseconds(100); if (timed_mtx.try_lock_for(timeout)) { std::cout << "获取锁成功\n"; // 执行操作... timed_mtx.unlock(); } else { std::cout << "获取锁超时\n"; // 替代方案... } } ``` **方法**: - `try_lock()`: 尝试获取锁,立即返回 - `try_lock_for()`: 尝试获取锁,带超时 - `try_lock_until()`: 尝试获取锁,直到指定时间点 ## 6. 共享互斥锁(std::shared_mutex) C++17 ```cpp #include <shared_mutex> std::shared_mutex sh_mtx; std::string shared_resource; // 读操作(多个线程可同时读) void reader(int id) { std::shared_lock lock(sh_mtx); std::cout << "Reader " << id << ": " << shared_resource << "\n"; } // 写操作(独占访问) void writer(const std::string& data) { std::unique_lock lock(sh_mtx); shared_resource = data; } int main() { std::thread readers[5]; for (int i = 0; i < 5; ++i) { readers[i] = std::thread(reader, i); } std::thread writer_thread(writer, "New Data"); for (auto& t : readers) t.join(); writer_thread.join(); } ``` **特性**: - 多个线程可同时获取共享锁(读锁) - 只有一个线程可获取独占锁(写锁) - 读写锁模式提高并发性能 ## 7. 避免死锁的最佳实践 1. **锁定顺序**:所有线程按相同顺序获取锁 2. **使用std::lock**:原子性地锁定多个互斥锁 3. **RAII包装器**:优先使用lock_guard/unique_lock 4. **避免嵌套锁**:减少锁定范围 5. **超时机制**:使用try_lock避免无限等待 ```cpp // 安全的多锁获取 void safe_multilock() { std::mutex mtx1, mtx2; // 方法1:使用std::lock std::unique_lock lock1(mtx1, std::defer_lock); std::unique_lock lock2(mtx2, std::defer_lock); std::lock(lock1, lock2); // 原子锁定 // 方法2:固定顺序 std::lock_guard lockA(mtx1); std::lock_guard lockB(mtx2); } ``` ## 8. 条件变量配合互斥锁 ```cpp std::mutex mtx; std::condition_variable cv; bool data_ready = false; // 生产者 void producer() { std::lock_guard<std::mutex> lock(mtx); // 准备数据... data_ready = true; cv.notify_one(); // 通知消费者 } // 消费者 void consumer() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return data_ready; }); // 等待通知 // 消费数据... data_ready = false; } ``` **工作流程**: 1. 消费者线程等待条件变量 2. 生产者修改条件并通知 3. 消费者被唤醒并检查条件 4. 条件满足则继续执行 ## 9. 性能考虑 1. **锁粒度**:尽量减小临界区范围 ```cpp // 错误:锁定时间过长 { std::lock_guard lock(mtx); auto data = get_data(); // 耗时操作 process(data); // 应在锁外执行 } // 正确:仅保护共享访问 auto data = get_data(); // 锁外执行 { std::lock_guard lock(mtx); update_shared_state(data); } ``` 2. **锁争用**:使用读写锁减少竞争 3. **无锁编程**:对于简单操作用原子变量替代 ```cpp std::atomic<int> counter(0); // 不需要锁的线程安全操作 counter.fetch_add(1, std::memory_order_relaxed); ``` ## 10. C++20新增特性 1. **std::scoped_lock**:改进的多锁RAII包装器 ```cpp std::mutex mtx1, mtx2; { std::scoped_lock lock(mtx1, mtx2); // C++17支持 // 自动解锁 } ``` 2. **等待通知增强**: ```cpp std::atomic<bool> ready(false); std::condition_variable cv; // C++20 等待通知 cv.wait(lock, std::atomic_wait, ready, false); ``` ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值