一步一步写线程之十六线程的安全退出之二例程
一、说明
在一篇分析了多线程的安全退出的相关机制和方式,那么本篇就针对前一篇的相关的分析进行举例分析。因为有些方法实现的方法类似,可能就不一一重复列举了,相关的例程主要以在Linux上的运行为主。
二、实例
线程间的同步,其实理解清楚动作的原理并不麻烦,麻烦的在于如何和业务较好的契和起来。直白的说就是用得恰到好处。所以下面的分析的方法,只是告诉大家这是一类手段,如何能更好的运用,才看开发者具体的要求是什么。
1、等待方式
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <signal.h>
#include <thread>
#include <unistd.h>std::atomic_bool quit = false;struct Data {int Display(int c) {std::cout << "Display value:" << c << std::endl;return c;}
};void threadWorkSleep(Data *d) {//模拟工作for (int c = 0; c < 10000; c++) {std::cout << "threadWorkSleep:call Data func:" << d->Display(c) << std::endl;}
}int main() {Data *pd = new Data;std::thread t = std::thread(threadWorkSleep, pd);t.detach();// firt:sleep thread safe quitsleep(1);return 0;
}
大家可以试着调整一下等待和模拟工作的时间,就可以发现具体的关系。实际的场景下,可能要求必须完成线程的工作才能退出。而如果等待时长不够,则线程就来不及完成相关的工作就退出了,那么,就没有实现业务的要求。等待的方式很粗暴,但也很简单。
2、轮询方式
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <signal.h>
#include <thread>
#include <unistd.h>std::atomic_bool quit = false;struct Data {int Display(int c) {std::cout << "Display value:" << c << std::endl;return c;}
};void threadWorkPolling(Data *d) {for (int c = 0; c < 10000; c++) {std::cout << "threadWorkPolling:call Data func:" << d->Display(c) << std::endl;}quit = true;
}int main() {Data *pd = new Data;// sec:Pollingstd::thread tp = std::thread(threadWorkPolling, pd);while (!quit) {std::cout << "polling quit:" << quit << std::endl;}std::cout << "polling thread safe quit.quit is:" << quit << std::endl;std::cout << "master thread thread!" << std::endl;// or deatchif (tp.joinable()) {tp.join();}return 0;
}
轮询的方式其实就是不断反复的查看是否可以退出了,这样做虽然安全,但浪费时间。就和现实社会一样,本来一个人干得活还得安排一个人去没事转转。
3、消息方式
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <signal.h>
#include <thread>
#include <unistd.h>std::atomic_bool quit = false;struct Data {int Display(int c) {std::cout << "Display value:" << c << std::endl;return c;}
};// third:msg or signal
static void sigHandler(int sigNo) {std::cout << "recv msg no is:" << sigNo << std::endl;if (sigNo == SIGUSR1) {quit = true;std::cout << "recv SIGUSR1" << std::endl;}
}
// third:msg or signal
void threadWorkMsg(Data *d) {for (int c = 0; c < 10000; c++) {std::cout << "threadWorkMsg:call Data func:" << d->Display(c) << std::endl;}int ret = raise(SIGUSR1);if (ret < 0) {std::cout << "SIGUSR1 msg send err!" << std::endl;}
}int main() {Data *pd = new Data;// msgsignal(SIGUSR1, sigHandler);std::thread ts = std::thread(threadWorkMsg, pd);ts.detach();while (!quit) {std::cout << "msg or signal quit:" << quit << std::endl;}std::cout << "polling thread safe quit.quit is:" << quit << std::endl;return 0;
}
这个信号的例程因为和其它程序共用的原因,把信号放到了主程序这样看起来也有点轮询的意思,其实如果把事件接收放到线程中反而更好体现这种情况。有兴趣可以试试。
4、事件方式
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <signal.h>
#include <thread>
#include <unistd.h>std::atomic_bool quit = false;struct Data {int Display(int c) {std::cout << "Display value:" << c << std::endl;return c;}
};// fourth:event
std::condition_variable conv;
std::mutex mt;
bool signaled = false;
void threadWorkEvent(Data *d) {for (int c = 0; c < 100; c++) {std::cout << "threadWorkEvent:call Data func:" << d->Display(c) << std::endl;}signaled = true;std::cout << "threadWorkEvent,set notify_one!" << std::endl;conv.notify_one();
}int main() {Data *pd = new Data;// eventstd::thread te = std::thread(threadWorkEvent, pd);te.detach();std::unique_lock<std::mutex> lock(mt);while (!signaled) {std::cout << "thread start wait....!" << std::endl;conv.wait(lock);}std::cout << "thread recv notify_one and quit wait!" << std::endl;std::cout << "master thread thread!" << std::endl;return 0;
}
其实这几个例程都非常简单,但可以一眼看明白几种手段的应用。可能老鸟儿们觉得没什么,但对于新手来说,可能还是非常有用的。其实真正复杂的在于线程结束时,相关的资源包括涉及到内存和IO等的处理。一个不小心这就出现各种问题。不过有了各个线程间互相协调的手段,就知道如何下手了。
三、总结
老生常谈的技术,可能对于不少开发者已经耳朵都听出茧子来了。可还是要说,为什么?这就和上学一样,你觉得你会了,而且你也明白了整个过程,甚至把作业都作得很好,可考试呢?大多数人仍然是一个中上游的水平。要是明白这个现象产生的道理,就明白现在这里说的什么道理。
熟能生巧,但很难产生思想!大家自己意会!
相关文章:
一步一步写线程之十六线程的安全退出之二例程
一、说明 在一篇分析了多线程的安全退出的相关机制和方式,那么本篇就针对前一篇的相关的分析进行举例分析。因为有些方法实现的方法类似,可能就不一一重复列举了,相关的例程主要以在Linux上的运行为主。 二、实例 线程间的同步,…...
【Linux系列】Shell 脚本中的条件判断:`[ ]`与`[[ ]]`的比较
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
ArcGIS+MIKE21 洪水淹没分析、溃坝分析,洪水淹没动态效果
洪水淹没分析过程: 一、所需数据: 1.分析区域DEM数据 二、ArcGIS软件 1.提取分析区域DEM(水库坝下区域) 2.DEM栅格转点 3.计算转换后几何点的x和y坐标值(精度20、小数位3) 4.导出属性表,形式…...
Git 的基本概念和使用
Git是一个分布式版本控制系统,它可以帮助开发人员追踪和管理代码的修改。下面是Git的基本概念和使用方式的解释: 仓库(Repository):Git使用仓库来存储代码和版本历史记录。仓库可以位于本地计算机上,也可以…...
*【每日一题 基础题】 [蓝桥杯 2024 省 B] 好数
[蓝桥杯 2024 省 B] 好数 好数 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数,我们就称之为“好数”。 给定一…...
对中文汉字排序的方法总结
写在前面 在各个系统中,都随处可见根据某个字段进行升序(ASC)或降序(DESC)进行排序展示。但进行中文汉字排序和查找的时候,对中文汉字的排序和查找结果往往都是错误的。 为了尽量提供全面的解决方法,本文会从各个层面出发告知有需要的人对应…...
【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘
学习爬虫时,遇到如下报错: 报错原因: 正则表达式的 search 或 finditer 方法没有找到任何匹配项,可能是换行符处理不当等。 解决方法如下: 在正则表达式末尾加上re.S即可,re.S是一个编译标志,…...
数据结构经典算法总复习(上卷)
第一章:数据结构导论 无重要考点,仅需了解时间复杂度。 第二章:线性表 1.获得线性表第i个元素 void GetElem_sq(SqList L, int i, ElemType &e) {if (i<1 || i>L.length) ErrorMsg("Invalid i value"); //注意错误监…...
JS获取URL中参数值的4种方法
方法1:现代浏览器都支持 URL 和 URLSearchParams 对象,可以很方便地从URL中提取参数 // 假设当前URL为 "https://example.com/?nameJohn&age30" const url new URL(window.location.href); // 或者你可以直接传入一个URL字符串 const …...
【面经】2024年软件测试面试题,精选100 道(附答案)
测试技术面试题 1、我现在有个程序,发现在 Windows 上运行得很慢,怎么判别是程序存在问题还是软硬件系统存在问题? 2、什么是兼容性测试?兼容性测试侧重哪些方面? 3、测试的策略有哪些? 4、正交表测试用…...
LabVIEW水泵性能测试系统
在现代工业应用中,水泵作为一种广泛使用的流体输送设备,其性能的可靠性对整个生产系统的稳定运行至关重要。通过LabVIEW软件配合专业硬件设备,设计了一套水泵性能测试系统,实现对各类水泵的综合性能测试与分析,提升水泵…...
React 第十九节 useLayoutEffect 用途使用技巧注意事项详解
1、概述 useLayoutEffect 是useEffect 的一个衍生版本,只是他们的执行时机不同 useLayoutEffect 用于在DOM更新执行完成之后,浏览器渲染绘制之前执行,这会阻塞浏览器的渲染; useEffect 的执行时机是在组件首次渲染和更新渲染之后…...
重温设计模式--2、设计模式七大原则
文章目录 1、开闭原则(Open - Closed Principle,OCP)定义:示例:好处: 2、里氏替换原则(Liskov Substitution Principle,LSP)定义:示例:好处&#…...
【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的?
【NLP高频面题 - Transformer篇】Transformer的位置编码是如何计算的? 重要性:★★★ NLP Github 项目: NLP 项目实践:fasterai/nlp-project-practice 介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用…...
基于SSM(Spring + Spring MVC + MyBatis)框架构建一个图书馆仓储管理系统
基于SSM(Spring Spring MVC MyBatis)框架构建一个图书馆仓储管理系统是一个涉及多个功能模块的项目,包括但不限于图书管理、读者管理、借阅管理、归还管理等。 1. 环境准备 确保你已经安装了以下工具和环境: Java Developmen…...
web的五个Observer API
IntersectionObserver: 一个元素从不可见到可见,从可见到不可见 ??IntersectionObserver是一种浏览器提供的 JavaScript API,用于监测元素与视窗的交叉状态。它可以告诉开发者一个元素是否进入或离开视窗,以及两者的交叉区域的…...
Java基础:抽象类与接口
1、抽象类和接口的定义: (1)抽象类主要用来抽取子类的通用特性,作为子类的模板,它不能被实例化,只能被用作为子类的超类。 (2)接口是抽象方法的集合,声明了一系列的方法…...
llama.cpp:PC端测试 MobileVLM -- 电脑端部署图生文大模型
llama.cpp:PC端测试 MobileVLM 1.环境需要2.构建项目3.PC测试 1.环境需要 以下是经实验验证可行的环境参考,也可尝试其他版本。 (1)PC:Ubuntu 22.04.4 (2)软件环境:如下表所示 工…...
Web前端基础知识(一)
前端是构建网页的一部分,负责用户在浏览器中看到和与之交互的内容。 网页是在浏览器中呈现内容的文档或页面。 通常,网页使用HTML、CSS、JavaScript(JS)组成。 HTML:定义了页面的结构和内容。包括文本、图像、链接等。 CSS:定义页面的样式…...
基于谱聚类的多模态多目标浣熊优化算法(MMOCOA-SC)求解ZDT1-ZDT4,ZDT6和工程应用--盘式制动器优化,MATLAB代码
一、MMOCOA-SC介绍 基于谱聚类的多模态多目标浣熊优化算法(Multimodal Multi-Objective Coati Optimization Algorithm Based on Spectral Clustering,MMOCOA-SC)是2024年提出的一种多模态多目标优化算法,该算法的核心在于使用谱…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
