C++ 互斥量、锁与条件变量详解

C++ 互斥量、锁与条件变量详解

C++ 互斥量、锁与条件变量详解

1. ‌互斥量(Mutex)

  • 定义‌:互斥量是C++多线程编程中用于保护共享资源的同步机制,确保同一时间只有一个线程可以访问特定代码段或资源。
  • 核心API‌:
    • std::mutex:基本互斥锁,需手动管理锁的生命周期。
    • std::lock_guard:RAII风格的锁管理,构造时自动上锁,析构时自动解锁。
    • std::unique_lock:更灵活的锁管理,支持手动控制锁的生命周期。

2. ‌锁(Lock)

  • 作用‌:锁是互斥量的执行单元,通过lock()unlock()方法控制对共享资源的访问。
  • 关键特性‌:
    • 独占性‌:同一时刻仅允许一个线程持有锁,其他线程尝试加锁时会阻塞或失败。
    • RAII‌:推荐使用std::lock_guardstd::unique_lock实现自动锁管理,避免死锁。

3. ‌条件变量(Condition Variable)

  • 定义‌:条件变量用于线程间等待特定条件成立并被其他线程唤醒的同步机制。
  • 核心API‌:
    • wait():阻塞线程直到被通知或条件成立。
    • notify_one():唤醒一个等待线程。
    • notify_all():唤醒所有等待线程。
  • 使用场景‌:线程A等待队列非空,线程B推入任务并通知A。

4. ‌典型用法示例

 

#include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 等待条件成立 std::cout << "Worker thread: Condition met!" << std::endl; } int main() { std::thread t(worker); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard<std::mutex> lock(mtx); ready = true; // 设置条件 } cv.notify_one(); // 唤醒等待线程 t.join(); return 0; }

 

5. ‌注意事项

 

  • 线程安全‌:互斥量和条件变量必须成对使用,确保线程安全。
  • 性能‌:std::lock_guardstd::unique_lock比原始lock()/unlock()更高效。
  • 虚假唤醒‌:条件变量可能因系统原因虚假唤醒,需重新检查条件。
总结‌:互斥量和锁是C++多线程编程中基础的同步手段,条件变量则用于更复杂的线程间通信。通过std::mutexstd::lock_guardstd::unique_lockstd::condition_variable实现高效且安全的线程同步。

 

互斥量与信号量区别

1. ‌核心概念

  • 互斥量(Mutex)‌:用于保护临界区,确保同一时刻只有一个线程访问共享资源。
  • 信号量(Semaphore)‌:用于线程间同步或资源计数控制,允许多个线程同时访问资源。

2. ‌主要区别

特性互斥量(Mutex)信号量(Semaphore)
用途保护临界区,防止资源竞争同步或资源计数控制
线程所有权持有线程必须释放无线程所有权限制
计数值二值(0/1)可初始化为 >1 的值
同时访问同一时刻仅允许一个线程访问可允许多个线程同时访问(计数值 > 1)
复杂性简单,专注于互斥更灵活,可用于多种同步场景

3. ‌关键特性对比

  • 互斥量‌:
    • 二值状态(0/1),仅允许一个线程持有。
    • 持有线程必须释放,避免死锁。
    • 优先级继承机制,解决优先级反转问题。
  • 信号量‌:
    • 计数值可为非负整数,允许多个线程同时访问。
    • 无线程所有权限制,可跨线程释放。
    • 无优先级继承机制,适用于资源计数控制。

4. ‌应用场景

  • 互斥量‌:保护共享资源,防止并发修改。
  • 信号量‌:实现资源池管理或线程同步。
总结‌:互斥量和信号量在功能上存在显著差异,互斥量专注于资源独占访问,信号量则用于资源计数和线程同步。选择时需根据具体需求(如是否允许多线程访问、是否需要优先级继承)来决定。

 

锁与条件变量

1. ‌锁(Lock)

锁是C++多线程编程中用于保护共享资源的同步机制,确保同一时间只有一个线程可以访问特定代码段或资源。核心类型包括:

  • std::mutex‌:基本互斥锁,需手动管理锁的生命周期。
  • std::lock_guard‌:RAII风格的锁管理,构造时自动上锁,析构时自动解锁。
  • std::unique_lock‌:更灵活的锁管理,支持手动控制锁的生命周期。

2. ‌条件变量(Condition Variable)

条件变量用于线程间等待特定条件成立并被其他线程唤醒的同步机制。核心API包括:

  • wait()‌:阻塞线程直到被通知或条件成立。
  • notify_one()‌:唤醒一个等待线程。
  • notify_all()‌:唤醒所有等待线程。

3. ‌典型用法示例

 

#include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 等待条件成立 std::cout << "Worker thread: Condition met!" << std::endl; } int main() { std::thread t(worker); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard<std::mutex> lock(mtx); ready = true; // 设置条件 } cv.notify_one(); // 唤醒等待线程 t.join(); return 0; }

 

4. ‌注意事项

 

  • 线程安全‌:锁和条件变量必须成对使用,确保线程安全。
  • 性能‌:std::lock_guardstd::unique_lock比原始lock()/unlock()更高效。
  • 虚假唤醒‌:条件变量可能因系统原因虚假唤醒,需重新检查条件。
总结‌:锁(std::mutexstd::lock_guardstd::unique_lock)用于资源保护,条件变量(std::condition_variable)用于线程间通信。通过RAII机制实现高效且安全的线程同步。

std::unique_lockstd::lock_guard 区别详解

1. ‌核心功能对比

特性std::lock_guardstd::unique_lock
设计目标简单、高效、不可手动控制锁灵活、支持手动控制锁、条件变量配合
RAII管理自动加锁/解锁,生命周期结束自动释放自动加锁/解锁,支持延迟加锁、手动控制
锁所有权无所有权转移,不可复制支持所有权转移(可移动)
条件变量不支持(需std::unique_lock支持(参数传递给std::condition_variable::wait()

2. ‌关键区别

  • 锁控制能力‌:
    • std::lock_guard:构造时立即加锁,析构时自动解锁,不支持中途释放或重新获取锁。
    • std::unique_lock:支持延迟加锁(std::defer_lock)、手动加锁/解锁(lock()/unlock()),适合复杂场景。
  • 所有权管理‌:
    • std::lock_guard:不可复制,不可转移(std::unique_lock可移动)。
    • std::unique_lock:支持所有权转移(std::move()),避免资源竞争。
  • 条件变量配合‌:
    • std::lock_guard:不支持(需std::unique_lock)。
    • std::unique_lock:可作为参数传递给std::condition_variable::wait(),实现线程间通信。

3. ‌典型用法示例

 

cppCopy Code

// 使用 std::lock_guard std::mutex mtx; void simple_lock() { std::lock_guard<std::mutex> lock(mtx); // 自动加锁 // 临界区代码 } // 自动解锁 // 使用 std::unique_lock void complex_lock() { std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟加锁 if (some_condition) { lock.lock(); // 手动加锁 } // 临界区代码 lock.unlock(); // 手动解锁 }

4. ‌适用场景

  • std::lock_guard‌:适用于简单作用域内全程需要锁的场景,如文件操作、数据结构修改。
  • std::unique_lock‌:适用于需要更灵活控制锁的场景,如条件变量等待、锁所有权转移。
总结‌:std::lock_guard提供简单高效的锁管理,std::unique_lock则提供更灵活的锁控制和条件变量支持。选择时需根据具体需求(如是否需延迟加锁、条件变量配合)来决定。

 

std::unique_lock条件变量

#include <iostream> #include <thread> #include <mutex> #include <condition_variable> std::mutex mtx; std::condition_variable cv; bool ready = false; void worker() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{ return ready; }); // 等待条件成立 std::cout << "Worker thread: Condition met!" << std::endl; } int main() { std::thread t(worker); std::this_thread::sleep_for(std::chrono::seconds(1)); { std::lock_guard<std::mutex> lock(mtx); ready = true; // 设置条件 } cv.notify_one(); // 唤醒等待线程 t.join(); return 0; }

 

  1. std::unique_lock提供lock()/unlock()接口,支持手动控制锁
  2. cv.wait(lock, pred):原子解锁lock,阻塞线程,等待通知或谓词成立
  3. wait退出后自动重新锁定lock,确保线程安全
  4. 支持延迟加锁(std::defer_lock),避免不必要的锁竞争
  5. std::condition_variable完美配合,实现高效线程间通信

Read more

【Python 量化入门】AKshare 保姆级使用教程:零成本获取股票 / 基金 / 期货全市场金融数据

【Python 量化入门】AKshare 保姆级使用教程:零成本获取股票 / 基金 / 期货全市场金融数据

做量化交易、财经数据分析、投资复盘的开发者和投资者,经常会遇到核心痛点:付费金融数据接口成本高、免费 API 注册流程繁琐、多市场数据分散难以整合。告别 QMT 回测烦恼!手把手教你搭建 MiniQMT+Backtrader 量化回测框架 本文就给大家详细讲解 Python 量化圈的开源神器AKshare,从安装到核心功能实战全覆盖,代码可直接复制运行,零基础也能一键获取全市场金融行情数据。 一、AKshare 是什么? AKshare 是一款基于 Python 开发的开源金融数据接口库,专为个人投资者、量化爱好者、财经数据分析人员打造,是目前国内生态最完善、维护最活跃的免费金融数据工具之一。 它支持股票、期货、基金、外汇、债券、指数、加密货币等多种主流金融市场的数据获取,核心优势如下: * 免费开源:完全开源免费,无隐藏收费,个人非商用零成本使用,无需开通付费会员 * 数据覆盖全面:A 股、

Python从0到100完整学习指南(必看导航)

Python从0到100完整学习指南(必看导航)

前言:零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能相关知识,成为学业升学和工作就业的先行者! 【优惠信息】 • 新专栏订阅前1000名享9.9元优惠 • 订阅量破1000后价格上涨至19.9元 • 订阅本专栏可免费加入粉丝福利群,享受: - 所有问题解答 - 专属福利领取 欢迎大家订阅专栏:零基础学Python:Python从0到100最新最全教程! 本文目录: * 一、Python基础与编程入门(第1-15篇) * 1.环境搭建与语法基础 * 2.数据结构基础篇 * 3.函数编程篇 * 二、面向对象与文件处理(第16-24篇) * 1.面向对象编程篇 * 2.标准库与文件处理篇 * 三、并发编程与网络爬虫(第25-39篇) * 1.并发编程基础篇

IoTDB Python原生接口全攻略:从基础读写到高级实战

IoTDB Python原生接口全攻略:从基础读写到高级实战

IoTDB Python原生接口全攻略:从基础读写到高级实战 做IoTDB时序数据开发的小伙伴,用Python对接肯定是高频需求,IoTDB官方的Python原生接口封装得特别友好,不管是基础的数据库连接、数据读写,还是高级的连接池管理、SSL加密、Pandas适配,全都能实现。今天就从环境搭建、基础使用,到DDL/DML操作、高级特性,再到测试和DBAPI适配,把IoTDB Python原生接口的用法一次性讲透,新手也能直接上手开发。 一、前期准备:安装依赖与包 用IoTDB Python原生接口前,得先装好两个核心依赖,一步到位不踩坑: 1. 安装thrift框架(要求版本≥0.13),是IoTDB底层的通信依赖 2. 安装IoTDB Python官方包(建议版本≥2.0),提供所有原生操作接口 直接用pip命令安装就行,执行以下两行: pip3 install thrift>=0.13 pip3

Python 入门超详细指南:环境搭建 + 核心优势 + 应用场景(零基础友好)

Python 入门超详细指南:环境搭建 + 核心优势 + 应用场景(零基础友好)

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 先搞懂:计算机与编程的核心概念 * 1.1 什么是计算机? * 1.2 什么是编程? * 二. 认识 Python:起源、优势与应用场景 * 2.1 Python 的 “前世今生” * 2.2 Python 的优缺点以及应用场景大盘点 * 三. Python 的就业前景:理性看待 “钱景” * 四. 环境搭建:Python+PyCharm(一步到位) * 4.1 安装 Python