Linux多进程和多线程(四)进程间通讯-定时器信号和子进程退出信号

  • 多进程(四)
    • 定时器信号
    • alarm()函数
    • 示例
    • alarm()函数的限制
    • 定时器信号的实现原理
    • setitimer()函数
    • setitimer()和alarm()函数的区别
      • setitimer()
        • old_value参数的示例
      • 对比alarm()
      • 区别总结:
  • 子进程退出信号
    • 示例:

多进程(四)

定时器信号

SIGALRM 信号是用来通知进程的定时器到期的。它是一个非可靠信号,即使进程捕获了它也不能保证定时器一定会到期。

定时器信号的使用场景:

  1. 定时器信号可以用来实现计时器功能。
  2. 定时器信号可以用来实现超时重试功能。
  3. 定时器信号可以用来实现定时任务功能。

在这里插入图片描述

alarm()函数

alarm()函数用来设置一个定时器,单位是秒。当定时器到期时,会向进程发送SIGALRM信号。
函数原型:

unsigned int alarm(unsigned int seconds);

返回值:

  • 如果成功设置定时器,则返回之前的定时器值(以秒为单位)。
  • 如果定时器未设置,则返回0。

参数说明:

  • seconds:定时器的秒数。

要点:

定时器的定时任务由内核完成, alarm 函数值负责设置定时时间, 并告诉内核启动定时器
当定时时间超时后,内核会向进程发出 SIGALRM 信号

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>//信号处理函数
void do_sig_alarm(int sig);
int main(){unsigned int ret;ret= alarm(5);//设置定时器,5秒,由内核来进行定时,时间结束后会发送SIGALRM信号printf("定时器返回: %d\n", ret);//ret为0,前一次设置定时器或者定时器时间已经用完//    ret= alarm(5);//设置定时器,5秒,由内核来进行定时
//    printf("定时器返回: %d\n", ret);//ret为5__sighandler_t r;//信号处理函数的返回值r=signal(SIGALRM,do_sig_alarm);if(r==SIG_ERR){//出错处理perror("signal");//出错处理exit(1);//退出程序}pause();//暂停程序,等待定时器超时,时间结束后会发送SIGALRM信号 默认是结束进程return 0;
}//信号处理函数
void do_sig_alarm(int sig){printf("收到定时器超时信号 : %d\n", sig);
}

alarm()函数的限制

  • 定时器信号是非可靠信号,即使进程捕获了它也不能保证定时器一定会到期。
  • 定时器信号只对进程有效,对子进程不起作用。
  • 定时器信号只对定时器设置的时间有效,不会影响到其他的定时器。

定时器信号的实现原理

  • 定时器信号是由内核来进行定时,并向进程发送SIGALRM信号。
  • 定时器信号的实现依赖于系统调用alarm()函数。
  • 定时器信号的实现原理是,内核在进程的进程控制块(PCB)中设置一个定时器,并将定时器的到期时间写入到进程的用户态的定时器中。
  • 当定时器到期时,内核向进程发送SIGALRM信号,进程捕获到信号后,可以执行定时器到期的任务。

setitimer()函数

setitimer()函数用来设置一个定时器,单位是秒。当定时器到期时,会向进程发送SIGALRM信号。


setitimer()和alarm()函数的区别

setitimer() 和 alarm() 函数在操作系统中都用于设置定时器,但它们有一些显著的区别:

setitimer()

setitimer() 函数更为灵活和精细,它可以设置三种类型的定时器,分别是:

ITIMER_REAL:实际时间定时器,当定时器到期时,会发送 SIGALRM 信号。

ITIMER_VIRTUAL:与进程在用户态下执行时间相关,当进程在用户态下运行时间到期时,会发送 SIGVTALRM 信号。

ITIMER_PROF:与进程在用户态和内核态下执行时间相关,当定时器到期时,会分别发送 SIGPROF 信号。

它的函数原型如下:

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
参数解释:
which:选择哪种定时器(ITIMER_REAL、ITIMER_VIRTUAL 或 ITIMER_PROF)。
new_value:指向一个 itimerval 结构,该结构指定定时器的初始响应时间和周期性时间间隔。
old_value:指向一个 itimerval 结构,如果不是 NULL,将返回先前的定时器设置。old_value是可选参数,如果不为 NULL,则函数调用成功后,old_value 结构将包含先前的定时器设置。itimerval结构体定义如下:
struct itimerval {struct timeval it_interval; /* 间隔时间 */struct timeval it_value;    /* 到期时间 */};timeval结构体定义如下:struct timeval {time_t tv_sec;    /* 秒 */suseconds_t tv_usec; /* 微秒 */};

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>void do_sig_alarm(int sig);int main(){struct itimerval itv;//定义定时器结构体itv.it_value.tv_sec=3;//设置定时器时间为5秒itv.it_value.tv_usec=0;//设置微秒为0itv.it_interval.tv_sec=5;//设置定时器间隔时间为5秒itv.it_interval.tv_usec=0;//设置微秒为0if(setitimer(ITIMER_REAL,&itv,NULL)!=0){//设置定时器perror("setitimer");exit(1);}__sighandler_t r;//信号处理函数的返回值r=signal(SIGALRM,do_sig_alarm);if(r==SIG_ERR){//出错处理perror("signal");//出错处理exit(1);//退出程序}while(1) {pause();//暂停程序等待信号}return 0;
}void do_sig_alarm(int sig){printf("收到定时器超时信号 : %d\n", sig);
}
old_value参数的示例

old_value参数用于返回setitimer()函数调用之前的定时器设置。这对于获取定时器的先前状态或恢复定时器的原始状态非常有用

示例程序,演示如何使用old_value参数来保存和恢复定时器的原始状态:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>// 定时器处理函数
void timer_handler(int signum) {printf("Timer expired\n");
}int main() {struct itimerval timer, old_timer;// 设置信号处理程序signal(SIGALRM, timer_handler);// 初始化新定时器设置timer.it_value.tv_sec = 5;        // 定时器第一次触发的时间(秒)timer.it_value.tv_usec = 0;       // 定时器第一次触发的时间(微秒)timer.it_interval.tv_sec = 1;     // 定时器周期性触发的时间间隔(秒)timer.it_interval.tv_usec = 0;    // 定时器周期性触发的时间间隔(微秒)// 设置新的定时器,并获取旧的定时器设置if (setitimer(ITIMER_REAL, &timer, &old_timer) == -1) {perror("setitimer");return 1;}// 打印旧的定时器设置printf("Old timer:\n");printf("it_value: %ld sec, %ld usec\n", (long)old_timer.it_value.tv_sec, (long)old_timer.it_value.tv_usec);printf("it_interval: %ld sec, %ld usec\n", (long)old_timer.it_interval.tv_sec, (long)old_timer.it_interval.tv_usec);// 等待定时器触发while (1) {pause(); // 让进程一直等待信号打断}return 0;
}

运行结果:

程序运行时会输出旧定时器的设置,并在5秒后第一次触发定时器,然后每秒触发一次,输出"Timer expired"。通过这种方式,你可以使用old_value参数来保存和恢复以前的定时器设置。

对比alarm()

alarm() 函数是一个简单的工具,用于设置一个秒级别的定时器,
当这个定时器到期时,操作系统会发送一个 SIGALRM 信号给调用进程。
它只有一种模式,而且只能设置一个定时器。

它的函数原型如下:

#include <unistd.h>
unsigned int alarm(unsigned int seconds);seconds:指定定时器的时间(秒)。

区别总结:

定时器类型:

setitimer() 支持三种定时器类型(实际时间、用户态时间、用户态和内核态时间),更灵活。
alarm() 只支持实际时间定时器。

精度:

setitimer() 支持微秒级精度。

alarm() 只支持秒级精度。

支持多个定时器:

setitimer() 可以同时设置和管理多个不同类型的定时器。

alarm() 只能设置一个定时器,后续调用会覆盖之前的定时器。

子进程退出信号

在使⽤ wait() 函数时,由于阻塞或者⾮阻塞都⾮常消耗资源,并且在阻塞情况下,⽗
进程不能执⾏其他逻辑

⼦进程退出是异步事件, 可以利⽤在⼦进程退出时,会⾃动给⽗进程发送 SIGCHLD 信号
在这里插入图片描述

示例:

void do_sig_child(int sig);int main(){pid_t cpid;//子进程id__sighandler_t r;//信号处理函数的返回值r=signal(SIGCHLD,do_sig_child);if(r==SIG_ERR){//出错处理perror("signal");//出错处理exit(1);//退出程序}cpid=fork();//创建子进程if(cpid==-1){//出错处理perror("fork");//出错处理exit(1);//退出程序}else if(cpid==0){//子进程printf("子进程pid: %d\n", getpid());sleep(5);//睡眠5秒exit(999);//退出子进程}else{//父进程printf("父进程pid: %d\n", getpid());//父进程不会因为等待子进程而阻塞,会继续往下执行while (1){}printf("父进程结束\n");}return 0;}
//子进程退出后会发送SIGCHLD, SIGCHLD默认处理方式是忽略的,内核现在会调用这个函数
void do_sig_child(int sig){printf("SIGCHLD处理函数: %s\n", strsignal(sig));//打印 : SIGCHLD处理函数: Child exitedwait(NULL  );//不会阻塞会立即释放子进程资源//通常情况下,当一个子进程终止时,它会进入一种称为“僵尸进程”的状态,// 保留一些必要的信息以便父进程能够获取其终止状态。// 如果父进程不调用 wait 或 waitpid 来获取该信息并释放资源,// 那么僵尸进程将一直存在,直到父进程终止。这会导致资源泄漏问题
}后会发送SIGCHLD, SIGCHLD默认处理方式是忽略的,内核现在会调用这个函数
void do_sig_child(int sig){printf("SIGCHLD处理函数: %s\n", strsignal(sig));//打印 : SIGCHLD处理函数: Child exitedwait(NULL  );//不会阻塞会立即释放子进程资源//通常情况下,当一个子进程终止时,它会进入一种称为“僵尸进程”的状态,// 保留一些必要的信息以便父进程能够获取其终止状态。// 如果父进程不调用 wait 或 waitpid 来获取该信息并释放资源,// 那么僵尸进程将一直存在,直到父进程终止。这会导致资源泄漏问题
}

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

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

相关文章

新声创新20年:无线技术给助听器插上“娱乐”的翅膀

听力损失并非现代人的专利&#xff0c;古代人也会有听力损失。助听器距今发展已经有二百多年了&#xff0c;从当初单纯的声音放大器到如今的全数字时代助听器&#xff0c;助听器发生了翻天覆地的变化&#xff0c;现代助听器除了助听功能&#xff0c;还具有看电视&#xff0c;听…

微信小程序 调色板

注意&#xff1a;是在uniapp中直接使用的一个color-picker插件&#xff0c;改一下格式即可在微信小程序的原生代码中使用 https://github.com/KirisakiAria/we-color-picker 这是插件的地址&#xff0c;使用的话先把这个插件下载下来&#xff0c;找到src&#xff0c;在项目创…

FreeRTOS和UCOS操作系统使用笔记

FreeRTOS使用示例 UCOS使用示例 信号量使用 信号量访问共享资源区/ OS_SEMMY_SEM; //定义一个信号量&#xff0c;用于访问共享资源OSSemCreate ((OS_SEM* )&MY_SEM, //创建信号量&#xff0c;指向信号量(CPU_CHAR* )"MY_SEM", //信号量名字(OS_SEM_CTR )1, …

imx6ull/linux应用编程学习(8)PWM应用编程(基于正点)

1.应用层如何操控PWM&#xff1a; 与 LED 设备一样&#xff0c; PWM 同样也是通过 sysfs 方式进行操控&#xff0c;进入到/sys/class/pwm 目录下 这里列举出了 8 个以 pwmchipX&#xff08;X 表示数字 0~7&#xff09;命名的文件夹&#xff0c;这八个文件夹其实就对应了…

守护矿山安全生产:AI视频分析技术在煤矿领域的应用

随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;其在煤矿行业的应用也日益广泛。AI视频智能分析技术作为其中的重要分支&#xff0c;为煤矿的安全生产、过程监测、效率提升和监管决策等提供了有力支持。 一、煤矿AI视频智能分析技术的概述 视频智慧煤矿AI…

数据库测试数据准备厂商 Snaplet 宣布停止运营

上周刚获知「数据库调优厂商 OtterTune 宣布停止运营」。而今天下班前&#xff0c;同事又突然刷到另一家海外数据库工具商 Snaplet 也停止运营了。Snaplet 主要帮助开发团队在数据库中生成仿真度高且合规的测试数据。我们在年初还撰文介绍过它「告别手搓&#xff01;Postgres 一…

Continual Test-Time Domain Adaptation--论文笔记

论文笔记 资料 1.代码地址 https://github.com/qinenergy/cotta 2.论文地址 https://arxiv.org/abs/2203.13591 3.数据集地址 论文摘要的翻译 TTA的目的是在不使用任何源数据的情况下&#xff0c;将源预先训练的模型适应到目标域。现有的工作主要考虑目标域是静态的情况…

Vue项目打包上线

Nginx 是一个高性能的开源HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它在设计上旨在处理高并发的请求&#xff0c;是一个轻量级、高效能的Web服务器和反向代理服务器&#xff0c;广泛用于提供静态资源、负载均衡、反向代理等功能。 1、下载nginx 2、…

探讨命令模式及其应用

目录 命令模式命令模式结构命令模式适用场景命令模式优缺点练手题目题目描述输入描述输出描述题解 命令模式 命令模式是一种行为设计模式&#xff0c; 它可将请求转换为一个包含与请求相关的所有信息的独立对象。 该转换让你能根据不同的请求将方法参数化、 延迟请求执行或将其…

【高级篇】第9章 Elasticsearch 监控与故障排查

9.1 引言 在现代数据驱动的应用架构中,Elasticsearch不仅是海量数据索引和搜索的核心,其稳定性和性能直接影响到整个业务链路的健康度。因此,建立有效的监控体系和掌握故障排查技能是每一位Elasticsearch高级专家的必备能力。 9.2 监控工具:洞察与优化的利器 在Elastics…

Rough.js在Vue3中生成随机蒙德里安风格的抽象艺术

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 Mondrian风格艺术生成器&#xff1a;用Vue和RoughJS创造抽象艺术 应用场景 Mondrian风格艺术以其大胆的色彩块和简单的几何形状而闻名。这种风格可以应用于各种设计项目&#xff0c;包括海报、插图和网页设计…

基于Web技术的教育辅助系统设计与实现(SpringBoot MySQL)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

Markdown+VSCODE实现最完美流畅写作体验

​下载VSCODE软件 安装插件 Markdown All in One &#xff1a;支持markdown的语言的&#xff1b; Markdown Preview Enhanced &#xff1a;观看写出来文档的效果&#xff1b; Paste IMage :添加图片的 Code Spell Checker检查英文单词错误&#xff1b; 基础语法 标题 #一个…

AI 会淘汰程序员吗?

前言 前些日子看过一篇文章&#xff0c;说国外一位拥有 19 年编码经验、会 100% 手写代码的程序员被企业解雇了&#xff0c;因为他的竞争对手&#xff0c;一位仅有 4 年经验、却善于使用 Copilot、GPT-4 的后辈&#xff0c;生产力比他更高&#xff0c;成本比他更低&#xff0c…

西南交通大学【算法分析与设计实验3】

实验3.3 任务分配问题 实验目的 &#xff08;1&#xff09;理解穷举法典型算法的求解过程。 &#xff08;2&#xff09;学习穷举法的时间复杂度分析方法&#xff0c;并通过实验验证算法的执行效率。 &#xff08;3&#xff09;学会如何利用穷举法求解具体问题&#xff0c;了…

按是否手工执行测试的角度划分:手工测试、自动化测试

1.手工测试&#xff08;Manual testing&#xff09; 手工测试是由人一个一个的输入用例&#xff0c;然后观察结果&#xff0c;和机器测试相对应&#xff0c;属于比较原始但是必须的一个步骤。 由专门的测试人员从用户视角来验证软件是否满足设计要求的行为。 更适用针对深度…

哈希表 | 哈希查找 | 哈希函数 | 数据结构 | 大话数据结构 | Java

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f4cc;毛毛张今天分享的内容&#x1f586;是数据结构中的哈希表&#xff0c;毛毛张主要是依据《大话数据结构&#x1f4d6;》的内容来进行整理&#xff0c;不…

程序化交易广告及其应用

什么是程序化交易广告&#xff1f; 程序化交易广告是以实时竞价技术即RTB&#xff08;real-time bidding&#xff09;为核心的广告交易方式。说到这里&#xff0c;你可能会有疑问&#xff1a;像百度搜索关键词广告还有百度网盟的广告&#xff0c;不也是CPC实时竞价的吗&#x…

创建kset

1、kset介绍 2、相关结构体和api介绍 2.1 struct kset 2.2 kset_create_and_add kset_create_and_addkset_createkset_registerkobject_add_internalkobject_add_internal2.3 kset_unregister kset_unregisterkobject_delkobject_put3、实验操作 #include<linux/module.…

kafka(一)原理(2)组件

一、broker 1、介绍 kafka服务器的官方名字&#xff0c;一个集群由多个broker组成&#xff0c;一个broker可以容纳多个topic。 2、工作流程 3、重要参数 参数名称 描述 replica.lag.time.max.ms ISR中&#xff0c;如果Follower长时间未向Leader发送通信请求或同步数据&a…