Unix信号处理

news2024/11/27 10:41:59

信号的基本概念我已经在上一节中简单介绍了,大家可以去看我的上一篇博客:

Unix中的进程和线程-2-CSDN博客

1.信号的产生

kill函数:

#include <signal.h>
#include <fcntl.h>
#include<t_stdio.h>
//自定义信号处理函数,n为信号编号
void handle(int n){
    printf("this is a test..\n");
    return;

}

int main(void){
    //从父进程继承信号处理函数
    //采用默认处理方式
    signal(2,SIG_IGN);//改变2号进程的处理函数,忽略2号信号
    signal(3,handle);//对3号信号使用自定义处理函数
    pid_t pid = fork();
    if(pid==-1)E_MSG("fork",-1);
    while(1);
    return 0;
}

  1. signal(2,SIG_IGN):使用signal()函数,将2号信号(通常是SIGINT,即Ctrl+C)的处理方式设置为忽略(SIG_IGN)。这意味着当程序接收到Ctrl+C时,不会终止程序,而是忽略该信号。
  2. signal(3,handle):将3号信号的处理方式设置为调用自定义的信号处理函数handle。这表示当程序接收到3号信号时(例如Ctrl+\),会执行handle函数中定义的操作。
  3. pid_t pid = fork();:创建一个子进程。
  4. if(pid==-1)E_MSG("fork",-1);:如果fork()调用失败,输出错误消息并退出程序。
  5. while(1);:在这个循环中,父进程和子进程都会进入一个无限循环,使得程序一直处于运行状态。

这个程序主要演示了信号处理的基本用法,以及父子进程之间对信号处理函数的继承。通过signal()函数可以设置特定信号的处理方式,可以是忽略该信号、采用默认的处理方式,或者调用自定义的信号处理函数。

 kill函数的仿写:

#include<t_stdio.h>
#include<t_file.h>
#include <sys/types.h>
#include <signal.h>

int main(int argc , char * argv[]){
    //将命令行的参数转化为整数类型
     kill (atoi(argv[2]),atoi(argv[1]));
    return 0;
}

 alarm函数:

alarm函数是一个用于在指定时间后发送信号的函数。它允许你在程序中设置一个定时器,当定时器计时时间到达后,系统会向当前进程发送一个 SIGALRM 信号。这通常用于实现超时控制或者周期性任务。

以下是 alarm 函数的声明:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);

alarm 函数接受一个 unsigned int 类型的参数 seconds,表示定时器的计时时间,单位是秒。当调用 alarm 函数后,系统会在指定的秒数之后向当前进程发送 SIGALRM 信号。

如果之前已经设置过定时器,调用 alarm 函数会取消之前的定时器,并设置新的定时器。如果 seconds 参数为 0,则之前设置的定时器会被取消,且不会设置新的定时器。

下面是一个简单的示例代码,演示了如何使用 alarm 函数实现一个定时器:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void handler(int signum) {
    printf("Received SIGALRM signal.\n");
    // 处理定时器触发后的逻辑
}

int main() {
    // 注册信号处理函数
    signal(SIGALRM, handler);

    printf("Setting up alarm for 5 seconds.\n");
    // 设置定时器为 5 秒
    alarm(5);

    // 进入一个无限循环
    while (1) {
        // 这里可以执行一些其他任务
        // 例如:等待用户输入等
    }

    return 0;
}

在这个示例中,首先注册了一个信号处理函数 handler,用于处理 SIGALRM 信号。然后调用 alarm(5) 设置了一个定时器,时间为 5 秒。当定时器计时时间到达时,系统会发送 SIGALRM 信号,进而触发信号处理函数 handler,在该处理函数中打印了一条消息。

  2.信号的暂停

如下:

#include<stdio.h>
#include <unistd.h>
#include<signal.h>
//信号处理函数
void handle(int n){}

unsigned int t_sleeps(unsigned int seconds){
    alarm(2);//设置一个两秒闹钟
    pause();//停止进程
    return alarm(0);//取消原来的脑子,返回未决时间

}

int main(void){
    //不能忽略SIGALRM信号,这样pause会一直起作用,不会停止
    //signal(SIGALRM,SIG_IGN);
    signal(SIGALRM,handle);

    while(1){
        t_sleeps(2);
        printf("nihao...\n");
    }
    return 0;
}

  1. #include<stdio.h>:包含了标准输入输出的头文件。
  2. #include <unistd.h>:包含了UNIX标准的头文件,其中包括了alarm()pause()函数的声明。
  3. #include<signal.h>:包含了信号处理相关的头文件。
  4. void handle(int n){}:定义了一个空的信号处理函数handle(),用于处理信号。在这个示例中,它并没有实际功能。
  5. unsigned int t_sleeps(unsigned int seconds):定义了一个自定义的睡眠函数t_sleeps(),它接受一个参数seconds,表示睡眠的秒数,并返回一个unsigned int类型的值,表示剩余的未决定时间。
  6. alarm(2);:调用alarm()函数,设置一个两秒的定时器。这会在两秒后向进程发送一个SIGALRM信号。
  7. pause();:调用pause()函数,使进程暂停,等待信号的到来。当接收到信号后,进程会恢复执行。
  8. return alarm(0);:取消之前设置的闹钟,并返回未决定的时间。

main()函数中:

  • 注册了信号处理函数,将SIGALRM信号的处理方式设置为handle函数。这一步通常是为了确保程序在接收到SIGALRM信号时不会终止。
  • 使用一个无限循环,调用t_sleeps(2)函数,表示每隔两秒打印一次"nihao..."。

这个程序的主要目的是演示如何使用alarm()pause()函数实现一个自定义的睡眠函数。当调用t_sleeps()函数时,程序会暂停执行两秒钟,然后继续执行后续的代码。

 3.信号阻塞和信号集

 3.1信号集的常用操作:

#include<signal.h>
#include<t_stdio.h>

int main(void){
    //定义信号集类型变量set
   __sigset_t set;
    //初始化set
    sigemptyset(&set);
    //将2号信号添加到信号集set中
    sigaddset(&set,2);
    sigaddset(&set,3);
    //测试3号信号是不是信号集中的一员
    int is=sigismember(&set,3);
    if(is==-1)E_MSG("sigismember",-1);
    if(is) 
        printf("signum is member of set..\n");
    else printf("signum is not member of set..\n");

    //将3号信号从信号集中移除
    sigdelset(&set , 3);
    is=sigismember(&set,3);
    if(is==-1)E_MSG("sigismember",-1);
    if(is) 
        printf("del signum is member of set..\n");
    else printf("del signum is not member of set..\n");

    return 0;
}

 信号的阻塞:

3.2进程的信号掩码集:

#include<t_stdio.h>
#include <asm-generic/signal-defs.h>
#include <bits/sigset.h>

int main(void){
    //定义信号集的变量set
    __sigset_t set;
    //初始化set
    sigemptyset(&set);
    //将2,3,9号信号添加到信号集set中
    sigaddset(&set,2);
    sigaddset(&set,3);
    sigaddset(&set,9);

    //将set设置为进程的信号掩码集
    int sm=sigprocmask(SIG_SETMASK,&set,NULL);
    if(sm==-1)E_MSG("sigprocmask",-1);
    while(1){}
    return 0;
}
  1. __sigset_t set;:定义了一个变量 set,类型为 __sigset_t,这是一个用于表示信号集的数据结构。
  2. sigemptyset(&set);:使用 sigemptyset() 函数将信号集 set 清空,确保其中不包含任何信号。
  3. sigaddset(&set,2);sigaddset(&set,3); 和 sigaddset(&set,9);:使用 sigaddset() 函数向信号集 set 中添加信号。在这里,将信号2、3和9添加到 set 中,分别代表 SIGINTSIGQUIT 和 SIGKILL 信号。
  4. int sm=sigprocmask(SIG_SETMASK,&set,NULL);:使用 sigprocmask() 函数将 set 中的信号设置为进程的信号掩码集。SIG_SETMASK 表示设置当前信号掩码为 set 中包含的信号集合,即阻塞信号2、3和9。如果设置成功,sigprocmask() 返回0;否则返回-1,并且相应的错误信息会被设置到 errno 中。
  5. while(1){}:进入一个无限循环,使得程序一直处于运行状态,以保持信号掩码的设置。

3.3未决信号集:

#include<t_stdio.h>
#include<signal.h>
#include <asm-generic/signal-defs.h>
#include<unistd.h>

int main(void){
    //定义信号集类型变量
    __sigset_t set , pset;
    //初始化信号集
    sigemptyset(&set);

    //添加信号到set
    sigaddset(&set,2);

    //将set设置为进程的信号掩码集
        int sm =sigprocmask(SIG_BLOCK,&set,NULL);
        if(sm==-1)E_MSG("sigismember",-1);
        while(1){
            sleep(1);
            //获取进程的未决信号集,pset存放的就是进程的未决信号集
            sigpending(&pset);
            int is=sigismember(&pset,2);
            if(is==-1)E_MSG("sigismemeber",-1);
            is? printf("yes..\n") : printf("no..\n");

        }

    return 0;
}
  1. 信号掩码集(signal mask): 信号掩码集是用于阻塞一组信号的,也就是说,被加入到该进程的信号掩码集中的信号,都会被阻塞,直到被从掩码集中移除。在你的代码中,通过sigprocmask(SIG_BLOCK,&set,NULL);将2号信号(SIGINT,即Ctrl+C触发的中断信号)加入到了掩码集中,从而阻塞了该信号。
  2. 未决信号集(pending signal): 未决信号集是指当前被阻塞,并且尚未处理的信号集合。只要这个信号在掩码集中,那么该信号一旦产生,就会被追加到未决信号集中,等待处理。在代码中,未决信号集的状态被周期性检查,并且每秒输出一次结果,显示2号信号是否存在于未决信号集中。 应用场景: 信号掩码集主要用于在处理某个信号时临时屏蔽其它会对当前处理过程产生干扰的信号,比如在处理某些复杂的业务逻辑或者关键数据更新时,防止被其它信号打断。 未决信号集则帮助我们得知哪些信号被阻塞且尚未得到处理,这对于调试程序,以及编写稳健的并发处理代码很有帮助。 

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

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

相关文章

深度学习算法概念介绍

前言 深度学习算法是一类基于人工神经网络的机器学习方法&#xff0c;其核心思想是通过多层次的非线性变换&#xff0c;从数据中学习表示层次特征&#xff0c;从而实现对复杂模式的建模和学习。深度学习算法在图像识别、语音识别、自然语言处理等领域取得了巨大的成功&#xf…

深入理解数据结构(3):栈和队列详解

文章主题&#xff1a;顺序表和链表详解&#x1f331;所属专栏&#xff1a;深入理解数据结构&#x1f4d8;作者简介&#xff1a;更新有关深入理解数据结构知识的博主一枚&#xff0c;记录分享自己对数据结构的深入解读。&#x1f604;个人主页&#xff1a;[₽]的个人主页&#x…

吴恩达机器学习笔记 三十一 K-means算法及优化目标 成本函数

随机初始化 K 个集群质心&#xff0c;这里设质心个数为2 第一步&#xff1a;分配点给集群质心 对 m 个 点&#xff0c;每个点对应的质心为 c(i) ,若离红色的质心近&#xff0c;则 c(i) 的值为1&#xff0c;否则为2。计算距离用的是L2范式。 第二步&#xff1a;移动集群质心 …

Verilog语法回顾--用户定义原语

目录 用户定义原语 UDP定义 UDP状态表 状态表符号 组合UDP 电平敏感UDP 沿敏感时序UDP 参考《Verilog 编程艺术》魏家明著 用户定义原语 用户定义原语&#xff08;User-defined primitive&#xff0c;UDP&#xff09;是一种模拟硬件技术&#xff0c;可以通过设计新的原…

Yolov7 Reid【附代码,行人重识别,可做跨视频人员检测】

本项目使用Yolov7Reid实现的行人重识别功能&#xff0c;可做跨视频人员检测。 应用场景&#xff1a; 可根据行人的穿着、体貌等特征的Reid算法在视频中进行检索&#xff0c;可以把这个人在各个不同摄像头出现时检测出来。可应用于犯罪嫌疑人检索、寻找走失儿童等。支持GUI界面…

Python API(happybase)操作Hbase案例

一、Windows下安装Python库&#xff1a;happybase pip install happybase -i https://pypi.tuna.tsinghua.edu.cn/simple 二、 开启HBase的Thrift服务 想要使用Python API连接HBase&#xff0c;需要开启HBase的Thrift服务。所以&#xff0c;在Linux服务器上&#xff0c;执行如…

scikit learn数据预处理学习笔记

数据集及基本操作 1&#xff09;数据集的组成 数据集由特征(feature)与标签(label)构成。 特征是输入数据。 什么是特征&#xff08;Features&#xff09;: 机器学习中输入数据&#xff0c;被称为特征。通常特征不止1个&#xff0c;可以用 n 维向量表示n个特征。 Features 数…

设备树语法

设备树语法 1 Devicetree格式1.1 DTS文件格式1.2 node格式1.3 properties格式 2 dts文件包好desi文件3 常用的 属性 properties3.1 #address-cells、#size-cells3.2 compatible3.3 model3.4 status3.5 reg&#xff08;设备不同reg属性的含义就不同&#xff09;3.6 name、device…

链式前向星解析

树形DP涉及到图存储&#xff0c;先复习一下链式前向星存储图&#xff0c;便于理解上篇的树形DP。对于图数据结构的存储&#xff0c;我们除了采用邻接矩阵&#xff08;消耗空间&#xff0c;不常用&#xff09;、邻接表&#xff0c;还有一种方法就是链式前向星。 链式前向星存储图…

数据结构——线性表(一)

线性表&#xff0c;顾名思义&#xff0c;是具有像线一样的性质的表。如同学生们在操场上排队&#xff0c;一个跟着一个排队&#xff0c;有一个打头&#xff0c;有一个收尾&#xff0c;在其中的学生都知道前一个是谁&#xff0c;后一个是谁&#xff0c;这样就像一根线将他们都串…

[HNCTF 2022 WEEK2]来解个方程?

标准的Z3题&#xff0c;可以拿来当模版题 题目逻辑很简单 直接看check from z3 import * # 初始化求解器 s Solver() # 定义6个未知数 n 24 x [Int(s str(i)) for i in range(0,24)] s.add(245 * x[6] 395 * x[5 ] 3541 * x[4 ] 2051 * x[3 ] 3201 * x[2 ] 1345 * x[7 ] 8…

中制交通安全统筹闪耀资本市场,成功上市引领行业新篇章

3月30日上午,随着上市钟声的敲响,中制(海南)交通安全统筹服务有限公司(股票代码:HK 31598)在香港股权交易展示中心挂牌上市,中制交通安全统筹董事长熊辉、联合创始人兼CEO张国伟、董事石杰等公司高管、股东、客户、合作伙伴出席挂牌仪式,共同见证敲钟上市,这也使中制交通安全统…

PonyAi Planning-横纵向轨迹规划

PonyAi Planning-横纵向轨迹规划 轨迹规划的探索和挑战 轨迹规划的概念安全舒适两不误&#xff1a;探讨优化算法在规划控制中的应用 轨迹规划的概念 决策 横向规划 纵向规划 优化算法在规划&#xff08;Planning&#xff09;中的应用 附赠自动驾驶学习资料和量产经验…

PP-YOLOE: An evolved version of YOLO

摘要 我们在之前 PP-YOLOv2 的基础上进行了优化&#xff0c;使用 无锚 范式&#xff0c;更强大的主干和颈部配备了 CSPRepResStage 。 ET-head 和动态标签分配算法 TAL 。 1 、介绍 受 YOLOX 的启发&#xff0c;我们进一步优化了之前的工作 PP-YOLOv2 。 PP-YOLOv2 是一款高…

使用hping3网络工具构造TCP/IP数据包和进行DDos攻击

1 概述 hping3是一个强大的命令行工具&#xff0c;用于生成、发送和解析TCP/IP协议的数据包。它是开源的网络安全工具&#xff0c;由Salvatore Sanfilippo开发&#xff0c;主要应用于网络审计、安全测试和故障排查等领域。hping3不仅可以作为普通的网络连通性检测工具&#xf…

深入理解数据结构(2):顺序表和链表详解

文章主题&#xff1a;顺序表和链表详解&#x1f331;所属专栏&#xff1a;深入理解数据结构&#x1f4d8;作者简介&#xff1a;更新有关深入理解数据结构知识的博主一枚&#xff0c;记录分享自己对数据结构的深入解读。&#x1f604;个人主页&#xff1a;[₽]的个人主页&#x…

数据结构——lesson12排序之归并排序

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

揭秘五力模型:轻松掌控企业竞争命脉,决策不再迷茫!

五力分析模型又成为波特五力模型是由著名的管理学者迈克尔波特(Michael Porter)在20世纪80年代初提出的一种理论框架&#xff0c;它对企业营销中的战略制定产生了全球性的深远影响。这一模型被广泛应用于企业竞争战略的分析&#xff0c;可以帮助企业有效地分析企业在营销环境中…

Java实验报告2

一、实验目的 本实验为Java课程的第二次实验&#xff0c;其主要目的如下&#xff1a; 理解继承和多态的概念&#xff1b; 掌握域和方法在继承中的特点&#xff1b; 掌握构造函数的继承和重载&#xff1b; 掌握this和super的用法&#xff1b; 二、实验原理 ​ 继承性是面…

上市公司-动态能力数据集(2008-2022年)

01、数据介绍 上市公司动态能力是指企业在不断变化的外部环境中&#xff0c;通过整合、创建和重构内外部资源&#xff0c;寻求和利用机会的能力。这种能力有助于企业重新构建、调配和使用其核心竞争力&#xff0c;从而保持与时俱进&#xff0c;应对市场挑战。具体来说&#xf…