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

一、说明

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

三、总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java 中的字符串

目录 Java 中的字符串字符串的创建字符串的比较字符串的拼接如何定义一个空的字符串 Java 中的字符串 字符串的创建 在 Java 中&#xff0c;可以通过以下几种方式创建字符串&#xff1a; 1.使用字符串字面量&#xff1a; String str "Hello, World!";2.使用 new…

数说故事聚焦“卖车”场景,推出AI汽车销售转化解决方案

没错&#xff0c;“卖车”我们也在行&#xff0c;为某车企“保住”了新车上市的订单。 深耕汽车行业多年&#xff0c;该车企10月份刚发布一款新能源车&#xff0c;其前期已经拥有了大量的保有客户和线上多渠道获取的潜在客户&#xff0c;然而&#xff0c;仍面临两大难题&#x…

javaEE-多线程编程-3

目录 java 常见的包 : 回调函数: 什么是线程: 第一个线程: 验证多线程执行: 内核: 调用sleep()方法: 执行结果分析: 线程创建的几种方式: 1.继承Thread类,重写run()方法. 2.实现Runnable接口,重写run()方法. 3.继承Thread类,重写run()方法.但使用匿名内部类 4.实现…

FFmpeg 框架简介和文件解复用

文章目录 ffmpeg框架简介libavformat库libavcodec库libavdevice库 复用&#xff08;muxers&#xff09;和解复用&#xff08;demuxers&#xff09;容器格式FLVScript Tag Data结构&#xff08;脚本类型、帧类型&#xff09;Audio Tag Data结构&#xff08;音频Tag&#xff09;V…

芯片级IO (Pad) Ring IP Checklist

SoC top顶层数字后端实现都会涉及到IO Ring &#xff08;PAD Ring&#xff09;的设计。这里面包括VDD IO,VDDIO IO, Signal IO, Corner IO&#xff0c;Filler IO&#xff0c;IO power cut cell等等。 数字后端零基础入门系列 | Innovus零基础LAB学习Day2 数字IC后端实现TOP F…

圣诞快乐(h5 css js(圣诞树))

一&#xff0c;整体设计思路 圣诞树h5&#xff08;简易&#xff09; 1.页面布局与样式&#xff1a; 页面使用了全屏的黑色背景&#xff0c;中央显示圣诞树&#xff0c;树形由三层绿色的三角形组成&#xff0c;每一层的大小逐渐变小。树干是一个棕色的矩形&#xff0c;位于三角…

Linux应用开发————mysql数据库表

mysql数据库表操作 查看表的结构 mysql> desc / describe 表名; 或者&#xff1a; mysql> show create table 表名; 常见数据库引擎&#xff1a; innodb, myISAM... 删除表 mysql> drop tabl…

移动网络(2,3,4,5G)设备TCP通讯调试方法

背景&#xff1a; 当设备是移动网络设备连接云平台的时候&#xff0c;如果服务器没有收到网络数据&#xff0c;移动物联设备发送不知道有没有有丢失数据的时候&#xff0c;需要一个抓取设备出来的数据和服务器下发的数据的方法。 1.服务器系统是很成熟的&#xff0c;一般是linu…

Unity中的委托和事件(UnityAction、UnityEvent)

委托和事件 &#x1f392;什么是委托&#xff0c;委托的关键字是Delegate&#xff0c;委托是一种函数的容器&#xff0c;运行将函数做为变量来进行传递 通过Delegate关键字我们声明了一个无参无返回的委托&#xff0c;通过这个委托我们可以存储无参无返回的函数 public deleg…

基于SpringBoot的“交流互动系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“交流互动系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能图 管理员登录界面图 个人信息界面图 个人…

LeetCode hot100-93

https://leetcode.cn/problems/longest-palindromic-substring/description/?envTypestudy-plan-v2&envIdtop-100-liked 5. 最长回文子串 给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。状态定义 我们用一个二维数组 dp[i][j] 表示子串 s[i…j] 是否是回文&…

C语言入门指南:从零开始的编程之路

记得我刚开始接触编程时,也像很多初学者一样充满疑惑。编程看起来很神奇,但要如何开始呢?经过多年编程经验的积累,今天和大家分享如何入门C语言编程。 C语言诞生于1972年,由Dennis Ritchie在贝尔实验室开发。它的出现彻底改变了计算机编程的历史。虽然现在有很多更新的编程语…

详解Redis的String类型及相关命令

目录 SET GET MGET MSET SETNX SET和SETNX和SETXX对比 INCR INCRBY DECR DECRBY INCRBYFLOAT APPEND GETRANGE SETRANGE STRLEN 内部编码 SET 将 string 类型的 value 设置到 key 中。如果 key 之前存在&#xff0c;则覆盖&#xff0c;⽆论原来的数据类型是什么…

SpringBoot使用 AOP 实现自定义日志记录并保存在Mysql

本文主要介绍在 Spring Boot 中使用 AOP 实现自定义日志记录并保存在 Mysql 的方法。先阐述记录日志的重要性及传统方式的弊端&#xff0c;提出新方式&#xff0c;即通过创建自定义注解、切面类等&#xff0c;将重要日志存到数据库&#xff0c;还给出了创建日志表、注解类、切面…

对golang的io型进程进行off-cpu分析

背景&#xff1a; 对于不能占满所有cpu核数的进程&#xff0c;进行on-cpu的分析是没有意义的&#xff0c;因为可能程序大部分时间都处在阻塞状态。 实验例子程序&#xff1a; 以centos8和golang1.23.3为例&#xff0c;测试下面的程序&#xff1a; pprof_netio.go package m…

CTF入门:以Hackademic-RTB1靶场为例初识夺旗

一、网络扫描 靶机ip地址为192.168.12.24 使用nmap工具进行端口扫描 nmap -sT 192.168.12.24 二、信息收集 1、80端口探索 靶机开放了80和22端口&#xff0c;使用浏览器访问靶机的80端口&#xff0c;界面如下&#xff1a; 点击target发现有跳转&#xff0c;并且url发生相应变…

腾讯云智能结构化OCR:以多模态大模型技术为核心,推动跨行业高效精准的文档处理与数据提取新时代

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大三学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

SD ComfyUI工作流 根据图像生成线稿草图

文章目录 线稿草图生成SD模型Node节点工作流程工作流下载效果展示线稿草图生成 该工作流的设计目标是将输入的图像转换为高质量的线稿风格输出。其主要流程基于 Stable Diffusion 技术,结合文本和图像条件,精确生成符合预期的线条艺术图像。工作流的核心是通过模型的条件设置…

Zabbix6.0升级为6.4

为了体验一些新的功能&#xff0c;比如 Webhook 和问题抑制等&#xff0c;升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档&#xff0c;确认组件要求的版本&#xff0c;否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…

网络安全概论——身份认证

一、身份证明 身份证明可分为以下两大类 身份验证——“你是否是你所声称的你&#xff1f;”身份识别——“我是否知道你是谁&#xff1f;” 身份证明系统设计的三要素&#xff1a; 安全设备的系统强度用户的可接受性系统的成本 实现身份证明的基本途径 所知&#xff1a;个…