Linuxc/c++之信号基础

简介: 这篇文章详细介绍了Linux下C/C++信号的基本概念、产生原因、处理过程、分类、注册与发送方法,以及信号屏蔽的机制。

1. 信号的本质

信号的本质就是整数,是用户模式下用来模拟硬件中断的一种方式。

硬件中断(真正中断):物理层面

软件中断(模拟中断):模拟

2. 信号的产生

  1. 硬件产生
  2. 内核产生
  3. 进程产生

3. 信号的处理过程

如果当前进程A正在运行,然后内核,硬件或者其它进程发送信号给进程A

进程A接收到信号之后:

1. 直接做信号本身规定的对应处理(例如SIGINT就是关闭进程(ctrl + C))

2. 做事先注册好的信号处理(信号注册函数signal(信号,处理函数))

3. 信号被屏蔽,等待信号屏蔽解除然后做出相应处理

4. 信号的分类

4.1 Linux提供的64个信号

kill -l

4.2 按照可靠性分类

不可靠信号:非实时性的信号 由UNIX提供的 1 --- 31

可靠信号:实时性的信号 后来扩充的 32 --- 64

4.3 按照类型分

标准信号:操作系统提供的信号

自定义信号:用户自定义的信号 SIG_USR

5. 信号注册与信号发送

5.1 信号注册

5.1.1 signal函数

不含signal 函数的一个进程, 使用Ctrl + C 或者 Ctrl + \ 可以结束当前进程

标准信号处理函数

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum,sighandler_t handler);

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

int main(){

    printf("pid: %d\n",getpid());

    int n = 0;
    while(1){
        printf(">> %d\n",n++);
        sleep(1);
    }

    return 0;
}

使用signal函数注册SIGINT信号后, 当注册SIGINT信号之后, 使用Ctrl + C 发送SIGINT信号就会调用自定义的信号处理函数

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

//SIGINT信号处理函数
void hand(int val){
    printf("val---%d\t想干掉我,没门!\n",val);   //val 为 signum  SIGINT的值为2
}

int main(){

    signal(SIGINT,hand); //注册信号处理(信号自己处理,不交给操作系统处理)
    printf("pid: %d\n",getpid());

    int n = 0;
    while(1){
        printf(">> %d\n",n++);
        sleep(1);
    }

    return 0;
}

5.1.2 sigaction函数(高级信号注册函数)

sigaction()高级信号注册函数对应sigqueue()高级信号发送函数

int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact)

参数一: 信号的id(例如SIGINT信号的signum 为 2)

参数二: 新的信号处理方式

参数三: 旧的信号处理方式

struct sigaction{

void (*sa_handler)(int); //原来的信号处理函数

void (*sa_sigaction)(int, siginfo_t *,void *); //高级的信号处理函数

sigset_t sa_mask; //信号屏蔽

int sa_flags; //使用原来的还是高级的信号处理函数

void (*sa_restorer)(void); //目前未使用

};

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

void hand(int n){
    printf("基本的信号处理函数!\n");
}
//参数1 信号   参数2 信号的一些信息(信号发送者给传入的数据)    参数3 注册信号传入的参数
void handler(int n,siginfo_t* siginfo,void* arg){
    printf("高级的信号处理函数!\n");
    printf("n:%d,msg:%d\n",n,siginfo->si_int);
}
int main(){
    printf("pid--->%d\n",getpid());
    struct sigaction act = {0};
    struct sigaction oldAct = {0};

    act.sa_handler = hand;      //信号处理函数
    act.sa_sigaction = handler;  //高级信号处理函数
    //sa_mask                    //信号屏蔽
    //*sa_restorer               //目前未使用
    act.sa_flags = SA_SIGINFO;  //sigaction替换handler

    //SIGINT
    sigaction(2,&act,&oldAct);  //注册高级信号处理
    //参数三作为返回值存在的

    int n = 0;
    while(1){
        printf(">>> %d\n",n++);
        sleep(1);
    }

    return 0;
}

5.2 信号发送

5.2.1 kill函数

kill(pid,sid); 参数1: 进程id 参数二: 信号

#include <stdio.h>
#include <unistd.h>
//信号的发送之kill函数
int aton(char* str){
    int num = 0;
    while(*str){
        num = num * 10 + (*str-'0');
        str++;
    }
    return num;
}

int main(int argc,char* argv[]){
    int pid = aton(argv[1]);   //进程id
    int sid = aton(argv[2]);   //信号id  2(SIGINT信号) 
    printf("%d %d",pid,sid);

//       进程id  信号id
    kill(pid,sid);
    return 0;
}

5.2.2 sigqueue函数(高级信号发送函数)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

int aton(char* str){
    int num = 0;
    while(*str){
        num = num * 10 + (*str-'0');
        str++;
    }

    return num;
}
int main(int argc,char* argv[]){
    int pid = aton(argv[1]);
    int sid = aton(argv[2]);

    union sigval u;
    u.sival_int = 6666666;

    sigqueue(pid,sid,u);

    return 0;
}

5.2.3 kill命令

kill sid -s pid

sid: 信号id pid: 进程id

6. 信号屏蔽

    **int sigprocmask(int how, const sigset\_t\* set, sigset\_t\* oldset);**

    **参数一: 是否屏蔽(或者其它的操作)  SIG\_BLOCK(屏蔽)  SIG\_UNBLOCK(不屏蔽)**

    **参数二: 指向信号集的指针,新设的信号集**

    **参数三: 指向信号集的指针,原来的信号集**

    **返回值: 成功返回 0**

    **int sigemptyset(sigset\_t\* set);  //信号集清空函数**

    **int sigfillset(sigset\_t\* set);   //将所有的信号添加进去**

    **int sigaddset(sigset\_t\* set, int signum);  //向信号集中添加一个信号**

    **int sigdelset(sigset\_t\* set,int signum);   //删除信号集中的一个信号**

    **int sigismember(const sigset\_t\* set, int signum); //判断某个信号是否在信号集中**
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

void hand(int n){
    printf("基本的信号处理函数!\n");
}
int main(){
    printf("pid: %d\n",getpid());
    sigset_t set,oldSet;
    sigemptyset(&set);     //清空信号集

    sigaddset(&set,2);
    //5秒钟不设置信号屏蔽
    signal(2,hand);
    sleep(5);
    //设置信号屏蔽20秒
    //sigismember  判断信号是否在信号集中
    int ret;
    if(1 == sigismember(&set,2)){
        printf("设置信号屏蔽!\n");
        ret = sigprocmask(SIG_BLOCK,&set,&oldSet);
        //参数1 屏蔽还是解除屏蔽
        //参数3为返回值  返回old信号集
        if(0 == ret) 
            printf("设置信号屏蔽成功!\n");
        else
            printf("设置信号屏蔽失败!\n");
    }
    sleep(20);
    //解除信号屏蔽
    if(1 == sigismember(&set,2)){
        printf("解除信号屏蔽!\n");
        ret = sigprocmask(SIG_UNBLOCK,&set,&oldSet);
        if(0 == ret) 
            printf("解除信号屏蔽成功!\n");
        else
            printf("解除信号屏蔽失败!\n");
    }
    while(1);

    return 0;
}

相关文章
|
27天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
3天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
372 16
|
19天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
23天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2594 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
5天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
182 2
|
3天前
|
编译器 C#
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
C#多态概述:通过继承实现的不同对象调用相同的方法,表现出不同的行为
105 65
|
7天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
332 2
|
23天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1580 17
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码