一步一步写线程之十六线程的安全退出之二例程

embedded/2024/12/23 8:15:17/

一、说明

在一篇分析了多线程的安全退出的相关机制和方式,那么本篇就针对前一篇的相关的分析进行举例分析。因为有些方法实现的方法类似,可能就不一一重复列举了,相关的例程主要以在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等的处理。一个不小心这就出现各种问题。不过有了各个线程间互相协调的手段,就知道如何下手了。

三、总结

老生常谈的技术,可能对于不少开发者已经耳朵都听出茧子来了。可还是要说,为什么?这就和上学一样,你觉得你会了,而且你也明白了整个过程,甚至把作业都作得很好,可考试呢?大多数人仍然是一个中上游的水平。要是明白这个现象产生的道理,就明白现在这里说的什么道理。
熟能生巧,但很难产生思想!大家自己意会!


http://www.ppmy.cn/embedded/147729.html

相关文章

汇编DOSBox 如何使文件可以运行

1.在vscode编写&#xff08;其他也可以&#xff09;如何在vscode中编写汇编语言并在终端进行调试(保姆级别&#xff09;_如何在vscode编译asm-CSDN博客 2.点击ML615中的DOS 2.1在命令行中输入命令 ml 文件名.asm ml 文件名.obj 2.2 将生成的exe文件移动到Assembly里面 这个文件…

3D开发工具HOOPS助力造船业加速设计与数字化转型

随着造船业对设计、高效精准建模和快速原型开发的需求不断增加&#xff0c;先进的3D技术逐渐成为推动行业创新的核心工具。Tech Soft 3D的HOOPS SDK作为行业领先的开发平台&#xff0c;已被NAPA、Herbert-ABS和三菱造船有限公司等全球造船业领导者所采用&#xff0c;帮助企业加…

双系统完美卸载Ubuntu

使用DiskGenius删除ubuntu的分区 删除引导项 diskpart list disk 查看C盘所在磁盘 select disk 1 选择指定的磁盘&#xff08;磁盘1 list partition 列出该磁盘上的所有分区 select partition 1 指定EFI系统分区 assign letterJ 给分区分配新盘符&#xff0c;电脑重启后J盘会自…

CMake 构建实例

CMake 构建步骤如下&#xff1a; 创建 CMakeLists.txt 文件&#xff1a;定义项目、目标和依赖。创建构建目录&#xff1a;保持源代码目录整洁。配置项目&#xff1a;使用 CMake 生成构建系统文件。编译项目&#xff1a;使用构建系统文件编译项目。运行可执行文件&#xff1a;执…

电脑问题4[非华为电脑安装华为电脑管家华为荣耀手机多屏协助]

非华为电脑安装华为电脑管家华为荣耀手机多屏协助 我是荣耀手机之前一直用的是window的"连接手机"功能,电脑控制手机还蛮好用,但是又不能够没有好的电脑控制手机的功能,后来想了想看了看,竟然安装了华为电脑关键,竟然可以顺利连接上荣耀手机,发现还蛮好用! 本文引用…

JavaScript网络请求( XMLHttpRequest 对象,进度事件, 跨源资源共享)

一、 XMLHttpRequest 对象 IE5 是第一个引入 XHR 对象的浏览器。这个对象是通过 ActiveX 对象实现并包含在 MSXML 库中 的。为此&#xff0c; XHR 对象的 3 个版本在浏览器中分别被暴露为 MSXML2.XMLHttp 、 MSXML2.XMLHttp.3.0 和 MXSML2.XMLHttp.6.0 。 所有现代…

网络安全笔记

# 网络安全概述 ### 网络安全的特征 - **机密性&#xff1a;信息不泄露给非授权的实体或对象** - **完整性&#xff1a;数据未经授权不能进行改变的特性&#xff0c; 即信息在存储或传输过程中保持不被修改&#xff0c;不被破坏的特性** - **可用性&#xff1a;可被授权实体访…

【Java 数据结构】List -> 给我一个接口!!!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. 什么是 List 2. List 常用的方法 3. List 的使用 1. 什么是 List 其实 List 是一个接口&#xff0c;它继承了 Collection 接口 下列为 List 接口中的各种…