《C++ 108好库》之2 多线程库thread,mutex,condition_variable,this_thread

《C++ 108好库》之之2 多线程库thread,mutex,condition_variable,this_thread

  • 《C++ 108好库》之2 多线程库thread,mutex,condition_variable,this_thread
  • std::thread类
  • ​​互斥量(Mutex)​​类
    • std::mutex​​类
    • std::lock_guard类
    • std::unique_lock类
  • ​​条件变量(Condition Variable)​​类
  • 获取线程ID和 延时
  • 使用例子
    • 创建线程
    • 使用mutex和Condition Variable的生产者-消费者模型

《C++ 108好库》之2 多线程库thread,mutex,condition_variable,this_thread

C++11 中,多线程编程通过标准库 正式引入,提供了跨平台的线程管理能力。
多线程一般由这些类合作构成:std::thread类、std::mutex​​类、std::lock_guard类、 std::unique_lock类、condition_variable类

std::thread类

1 ​​创建线程​​
explicit thread(_Callable&& __f, _Args&&… __args)
使用 std::thread类创建线程,构造函数接受函数对象及参数:
向线程函数传递参数时,参数会被复制到线程的独立内存中;如果希望传递引用,需要使用std::ref。

2​​线程管理​​:
join():等待线程完成。
detach():将线程与主线程分离,使其独立运行。一旦分离,就不能再与之通信。
注意:在销毁std::thread对象之前,必须调用join()或detach(),否则程序会终止(调用std::terminate)。

​​互斥量(Mutex)​​类

C++11提供了std::mutex用于保护共享数据,防止数据竞争。

std::mutex​​类

std::mutex()

std::mutex::lock() :调用此函数会尝试​​锁定​​互斥体。
行为:​​如果互斥体当前​​未被任何线程锁定​​,则调用线程获得锁,函数立即返回。如果互斥体​​已被其他线程锁定​​,则调用线程会被​​阻塞​​(挂起),直到持有锁的线程解锁该互斥体。一旦解锁,等待的线程之一(取决于调度)会获得锁并继续执行。
​​特点:​​ 阻塞调用。如果忘记解锁会导致死锁。
​​用法:​​ 当你需要确保临界区被独占访问,并且可以接受线程阻塞等待时使用。

std::mutex::try_lock(): 调用此函数会​​尝试​​锁定互斥体,但​​不会阻塞​​调用线程。
​​行为:​​如果互斥体当前​​未被锁定​​,则调用线程获得锁,函数返回 true。如果互斥体​​已被锁定​​(无论是当前线程还是其他线程),则函数​​立即返回 false​​,线程继续执行而不会被阻塞。
​​特点:​​ 非阻塞调用。需要检查返回值来判断是否成功获得锁。
​​用法:​​ 当你需要在锁不可用时做其他事情,避免阻塞线程时使用。常用于轮询、避免死锁策略(如按固定顺序获取多个锁失败时释放已持有的锁)或非关键路径的优化。

std::mutex::unlock():解锁

std::lock_guard类

它在构造时自动锁定给定的互斥体,并在析构时(通常是离开作用域时)自动解锁它。
​​构造时:​​ 调用传入的互斥体(如 std::mutex)的 lock()方法。这会阻塞直到获得锁。
​​析构时:​​ 调用互斥体的 unlock()方法。
用法:std::lock_guardstd::mutex lock(mtx); // 构造时自动调用 mtx.lock()

std::unique_lock类

功能比 lock_guard​​更强大、更灵活​​。它也管理互斥体的锁定和解锁,但提供了更多的控制选项。
​​行为/特点:​​
​​灵活的构造:​​默认构造:创建一个不关联任何互斥体的 unique_lock。
关联互斥体并立即锁定(阻塞):unique_lock lock(mtx);(等价于 lock_guard)
关联互斥体但​​延迟锁定​​:unique_lock lock(mtx, std::defer_lock);构造时不锁定,稍后手动调用 lock(), try_lock()或 try_lock_for()/try_lock_until()(针对 std::timed_mutex)。
关联互斥体并尝试锁定:unique_lock lock(mtx, std::try_to_lock);构造时调用 mtx.try_lock()。
关联互斥体并假设已锁定(接管所有权):unique_lock lock(mtx, std::adopt_lock);假设调用线程已经持有 mtx的锁,unique_lock负责后续解锁。
手动控制:​​
lock(): 阻塞锁定关联的互斥体(如果尚未锁定)。
try_lock(): 尝试非阻塞锁定关联的互斥体。
unlock(): ​​手动解锁​​关联的互斥体,在 unique_lock析构前可以临时释放锁(这在 lock_guard中是不可能的)。析构时如果互斥体仍被该 unique_lock持有,会自动解锁。
release(): 释放对互斥体的所有权管理(返回互斥体指针),不再负责解锁。调用者需手动管理。
​​所有权:​​
可移动 (std::move),但不可复制。锁的所有权可以在 unique_lock对象之间转移。
​​条件变量:​​ std::condition_variable::wait等函数​​必须​​使用 std::unique_lockstd::mutex作为参数,因为它需要能在等待时解锁和重新锁定互斥体(这是 lock_guard做不到的)。

​​条件变量(Condition Variable)​​类

<condition_variable>
用于线程间的同步,允许线程在某些条件不满足时休眠,直到被其他线程通知。通常与互斥量一起使用。
void notify_one() noexcept;
void notify_all() noexcept;
wait(unique_lock& __lock) noexcept;
wait_until(unique_lock& __lock,const chrono::time_point<__clock_t, _Duration>& __atime)
wait_for(unique_lock& __lock, const chrono::duration<_Rep, _Period>& __rtime)

获取线程ID和 延时

std::this_thread里的函数
inline thread::id get_id()
获取​​当前执行线程的唯一标识符​​。
std::thread::id main_id = std::this_thread::get_id(); // 输出示例:0x70000a15c000

inline void sleep_for(const chrono::duration<_Rep, _Period>& __rtime)
使​​当前线程阻塞​​一段指定的​​相对时间​​。
std::this_thread::sleep_for(std::chrono::seconds(1));

inline void sleep_until(const chrono::time_point<_Clock, _Duration>& __atime)
使​​当前线程阻塞​​直到​​绝对时间点​​。

使用例子

创建线程

std::thread thread_hello(hello,"LiHua");
thread_hello.join();

传入函数给线程
void hello(const std::string str) {
std::cout << "hello world! "<<str<<std::endl;
}

使用mutex和Condition Variable的生产者-消费者模型

std::thread thread_producer(producer);
thread_producer.detach();std::thread thread_consumer(consumer);
thread_consumer.join();

其中的线程函数

std::queue<int> dataQueue;
std::mutex mtx_test_thread;
std::condition_variable cv_test_thread;
void producer() {for (int i = 0; i < 50; ++i) {{std::lock_guard<std::mutex> lock(mtx_test_thread);dataQueue.push(i); std::cout << "push:" << i << std::endl;}std::this_thread::sleep_for(std::chrono::seconds(1));cv_test_thread.notify_one(); // 通知消费者}
}void consumer() {while (true) {std::unique_lock<std::mutex> lock(mtx_test_thread);cv_test_thread.wait(lock, [] { return !dataQueue.empty(); });int value = dataQueue.front();dataQueue.pop();lock.unlock();if (value == -1) break; // 终止条件std::cout << "Consumed: " << value << std::endl;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96136.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android系统框架知识系列(二十):专题延伸:JVM vs ART/Dalvik - Android运行时演进深度解析

​关键词​&#xff1a;运行时优化、AOT编译、JIT编译、内存管理、电池效率、性能分析一、Android运行时演进背景1. 移动环境的特殊挑战Android运行时环境的演进源于移动设备的独特限制&#xff1a;​移动设备约束条件​&#xff1a;​有限的内存资源​&#xff1a;早期设备仅1…

ubuntu 22 安装轻量级桌面Xfce并使用xrdp远程桌面连接

1.安装Xfce:sudo apt install xubuntu-desktop -y2.安装xrdp:sudo apt install xrdp -y3.配置xrdp&#xff0c;nano /etc/xrdp/xrdp.ini:[Globals] ... port3389 ; 远程连接端口&#xff0c;默认是3389&#xff0c;可以改成自己喜欢的端口... ; ; Session types ;; Some sess…

【Flask】测试平台开发,数据看板开发-第二十一篇

概述&#xff1a;在前面我们已经实现了我们的产品创建管理&#xff0c;应用管理管理&#xff0c;需求提测管理但是每周提测了多少需求&#xff0c;创建了哪些产品&#xff0c;我们是不是看着不是很直观&#xff0c;接下来我们就需要开发一个数据看板功能&#xff0c;实现能够看…

我是程序员,不是程序猿:请别把我当猴耍——拒绝被低估,用专业赢得尊重

摘要 本文旨在深度剖析“程序员”与“程序猿”一字之差背后所反映的职业尊严与身份认同问题。我们生活在一个技术驱动的时代&#xff0c;但对技术创造者的认知却常常被“程序猿”、“码农”等标签简单化、甚至矮化。本文将从正名开始&#xff0c;辨析“程序员”的专业内涵&…

C++中vector删除操作的安全隐患与最佳实践

std::vector 是C标准模板库&#xff08;STL&#xff09;中最常用的动态数组容器&#xff0c;提供了高效的随机访问和动态扩容能力。然而&#xff0c;其删除操作如果使用不当&#xff0c;会引入严重的安全隐患&#xff0c;包括未定义行为、内存泄漏和数据竞争等问题。本文将深入…

Unix/Linux 系统中的 `writev` 系统调用

<摘要> 本文对 Unix/Linux 系统中的 writev 系统调用进行了全面深入的解析。内容涵盖了其产生的背景&#xff08;从传统 write 的局限性到分散/聚集 I/O 概念的引入&#xff09;、核心概念&#xff08;如 struct iovec、系统调用流程&#xff09;。重点剖析了其设计意图&…

深入理解 Android targetSdkVersion:从 Google Play 政策到依赖冲突

深入理解 Android targetSdkVersion&#xff1a;从 Google Play 政策到依赖冲突 作为 Android 开发者&#xff0c;你很可能在 Android Studio 中见过这条提示&#xff1a;Google Play requires that apps target API level 33 or higher。它像一个尽职的提醒者&#xff0c;时常…

灰匣(GrayBox)1.0.0 发布【提升系统权限APP】

灰匣是一个提升系统权限的工具&#xff0c;可以配合Root、三方软件&#xff08;Shizuku&#xff09;以及【设备管理员】&#xff08;设备所有者&#xff09;实现一些高级功能及底层接口&#xff0c;可以自动隔离&#xff08;冻结/禁用&#xff09;不必要的应用&#xff0c;如某…

PAT 1104 Sum of Number Segments

这一题的大意就是找一个数组中的所有子数组&#xff0c;它们的累加和为多少&#xff0c; 题目上给出的数据范围是O(n^5)那么只能遍历一次&#xff0c;不能用暴力的方法求出。 看到这一题我有两个思路&#xff1a; 1.试图用双指针和滑动窗口来把O&#xff08;n^2)的时间复杂度降…

[万字长文]AJAX入门-常用请求方法和数据提交、HTTP协议-报文、接口文档、案例实战

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在VS code中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 HTML、CSS、JavaScript系列文章 已经收录在前端专栏&#xff0c;有需要的宝宝们可以点击前端专栏查…

Codesy中的UDP发送信息

Codesy UDP通讯 概述 CAA Net Base Services UDP通讯的建立 发送UDP 状态控制 效果 概述 Codesys中默认安装的通讯支持很多,不安装其他的软件也可以实现TCP通讯。但是,在使用UDP通讯时,因为我们的PLC有两个网卡,一般我们把第一个网口做编程和HMI用,把的个网口做外部通讯,…

神经网络之深入理解偏置

&#x1f50d; 1. 表达能力&#xff1a;无偏模型不能表示全体函数族 ✔ 有偏线性变换&#xff1a; yWxb&#xff08;仿射变换&#xff09; y Wx b \quad \text{&#xff08;仿射变换&#xff09;} yWxb&#xff08;仿射变换&#xff09; 能表示任意线性函数 平移是仿射空间的…

小白必看:AI智能体零基础搭建全攻略!

写在前面&#xff1a;别怕&#xff0c;真的不需要技术背景&#xff01; 你是不是经常听到"AI智能体"、"大模型"这些高大上的词&#xff0c;总觉得那是技术大牛的专利&#xff1f;别担心&#xff0c;这篇教程就是为你准备的&#xff01;我们将用最通俗的语…

React state在setInterval里未获取最新值的问题

目录 一、问题描述 二、解决方案 方案一&#xff0c;使用函数式更新 方案二&#xff0c;使用 useRef 保存最新值 一、问题描述 在 React 中&#xff0c;当在 setInterval或setTimeout 中使用 setState 时&#xff0c;经常会遇到状态不是最新值的问题。这是因为闭包导致的&a…

x86 架构 Docker 镜像迁移至 ARM 环境的详细指南

目录 一、问题背景与分析 二、解决步骤 &#xff08;一&#xff09;检查 docker-compose 版本 &#xff08;二&#xff09;升级 docker-compose 1. 对于 Linux 系统 2. 对于 Windows 系统 &#xff08;三&#xff09;验证升级 &#xff08;四&#xff09;重新运行 dock…

零代码部署工业数据平台:TRAE + TDengine IDMP 实践

对于编程初学者来说&#xff0c;软件开发流程中的开发环境配置、安装异常或报错往往需要花费大量时间查阅资料和反复试错&#xff0c;才能正常安装和启动某些软件工具。现在&#xff0c;在 TRAE 的帮助下&#xff0c;即使完全没有接触过编程&#xff0c;也能通过自然语言直接表…

史上最全Flink面试题(完整版)

1、简单介绍一下 FlinkFlink 是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务&#xff1a;DataSet API&#xff0c; 对静态数…

C# .NET中使用log4Net日志框架指南

C# .NET中使用log4Net日志框架指南 log4Net是Apache基金会开发的一款高效、灵活的日志记录框架&#xff0c;广泛应用于.NET生态系统中。它支持多种日志输出目标&#xff08;如文件、数据库、控制台&#xff09;&#xff0c;并提供细粒度的日志级别控制&#xff0c;帮助开发者监…

每日算法刷题Day68:9.10:leetcode 最短路6道题,用时2h30min

一. 单源最短路&#xff1a;Dijkstra 算法 1.套路 1.Dijkstra 算法介绍 (1)定义 g[i][j] 表示节点 i 到节点 j 这条边的边权。如果没有 i 到 j 的边&#xff0c;则 g[i][j]∞。 (2)定义 dis[i] 表示起点 k 到节点 i 的最短路长度&#xff0c;一开始 dis[k]0&#xff0c;其余 …

Spring Boot + Apache Tika 从文件或文件流中提取文本内容

应用效果&#xff1a;1、安装 Apache Tika 依赖pom.xml<!-- Apache Tika 从文件中提取结构化文本和元数据 --><dependency><groupId>org.apache.tika</groupId><artifactId>tika-core</artifactId><version>2.9.2</version>&l…