Linux系统编程系列之进程间通信(IPC)-信号

一、什么是信号

        信号是进程间通信的一种方式,它是异步通信的。而异步的意思就是不同步,事件的发生和处理没有协同。

二、信号的特性

             Linux/Unix系统下,信号总共分成两大类,一类是最常用的标准信号,另一类是后面的引入的实时信号。一共有62个信号,前31个是标准信号,后面31个是实时信号。注意没有32,33号。

        1、标准信号

        (1)不排队,信号的响应会相互嵌套。

        (2)如果目标进程没有及时响应,那么随后到达的相同信号将会被丢弃。

        (3)每个信号都对应一个系统事件(除了SIGUSR1和SIGUSR2),当这个事件发生时,将产生这个信号。

        (4)在进程的挂起信号中,进程会优先响应实时信号。

        2、实时信号

        (1)实时信号的响应次序按接收顺序排队。如果收到相同的信号的则不会嵌套,但是如果是不同的信号则会导致嵌套。

        (2)即使相同的实时信号被同时发送多次,也不会被丢弃,而会依次按个响应。

        (3)实时信号没有特殊的系统事件与之对应。

        (4)实时信号在挂起队列中信号值越大,优先级越高。

三、信号的生命周期

        所谓信号的生命周期,指的是信号从产生到被响应完毕的整个过程,这个过程可被描述为:

        1、信号的产生

        信号既可以由特定的事件产生(比如发生了内存访问异常导致产生信号SIGSEGV),也可以由用户主动发起(比如调用了kill()函数),不管是哪种方式产生的信号,其本质都是触发了内核的信号发生器,并向特定进程(即目标进程)传递的过程。

// kill()函数接口介绍
#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

参数:
    pid: 要接收信号的进程号
    sig: 信号的编号
返回值:成功返回0, 失败返回-1.

        2、信号的挂起

        每个进程都保留有一个挂起信号集,所有被发送到这个进程的信号首先被放入到这个信号集(进程处于非执行状态),挂起信号集存储了进程的待处理信号,这些信号必须要等到进程被系统调度(占用CPU执行的时候),真正执行的时候才能被进一步响应。

        3、信号的响应(处理)

        信号的响应总共有如下四种方式:

        (1)屏蔽(阻塞):延缓对信号的响应,直到解除对该信号的屏蔽为止。

        (2)捕捉:执行一个预先设置的与信号相关联的响应函数。

        (3)默认:按信号默认的情况处理。

        (4)忽略:直接丢弃该信号。

注意:系统中9号,19号信号是不允许被挂起或捕获的,只允许对他们进行默认处理

四、信号的响应(处理)        

       1、信号的捕捉

        给函数指定关联函数的接口是:        

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

// 翻译过来就是
void (*signal(int sig, void (*func)(int)))(int);

// 函数名为:signal
// 参数为:
    int sig, 信号的编号
    void (*func)(int), 关联的函数,函数的参数是int, 返回值是void
// 返回值:void (*)(int);

        2、信号的默认处理

        如果程序没有对信号做任何预先准备,那么当信号到达时,则会按照信号的默认规则进行响应,具体默认规则可使用如下命令查阅:

man 7 signal

     列表中的Action 一列就是系统对信号的默认处理规则,默认规则如下:

        (1)Term:中断目标进程

        (2)Core:中断目标进程,且产生核心转储文件core

        (3)Stop:暂停目标进程,直到收到信号SIGCONT

        (4)Cont:恢复目标进程运行

        (5)Ign:忽略信号

          3、信号的忽略

信号的忽略就是直接将收到的信号丢弃

signal(SIGINT, SIG_IGN);

          4、信号的屏蔽

屏蔽信号实际上就是暂缓对信号的响应,采用如下函数进行对信号的屏蔽

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

// 参数解析:
1、how:操作命令字,比如阻塞、解除阻塞等
    SIG_BLOCK:阻塞set中的信号(原有正在阻塞的信号保持阻塞)
    SIG_SETMASK:阻塞set中的信号(原有正在阻塞的信号自动解除)
    SIG_UNBLOCK:解除set中的信号

2、set:当前要操作的信号集
3、oldset:若为非空,则将原有阻塞信号集保留到该oldset中
注意:该函数的操作参数不是单个信号,而是信号集,
这意味着我们可以同时对多个信号设置阻塞或者解除阻塞


// 信号集操作函数组
int sigemptypset(sigset_t *set);    // 清空信号集set
int sigfillset(sigset_t *set);    // 将所有信号加入信号集set中
int sigaddset(sigset_t *set, int signum); // 将信号signum添加到信号集set中
int sigdelset(sigset_t *set, int signum); // 将信号signum从信号集set中剔除
int sigsimember(const sigset_t *set, int signum); // 测试信号signum是否在信号集set中

五、案例

        1、信号的捕捉

// 信号的捕捉操作示例

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

void func(int sig)
{
    printf("call func\n");
    printf("catch signal:%d\n", sig);
}

int main(int argc, char *argv[])
{
    // 设置信号响应函数,捕捉34号信号,当捕获到34号信号时,执行func函数
    // 注意设置后,不会执行func函数,signal()应该尽量写在前面
    signal(34, func);   

    printf("my pid is %d\n", getpid()); // 打印本进程ID号,方便从命令行发送信号
    printf("set signal 34...\n");

    while(1)
    {
        sleep(1);
    }
    
    return 0;
}

 

// 信号的捕捉操作示例

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

void func(int sig)
{
    printf("call func\n");
    printf("catch signal:%d\n", sig);
}

int main(int argc, char *argv[])
{
    printf("my pid is %d\n", getpid()); // 打印本进程ID号,方便从命令行发送信号
    printf("set signal 34...\n");

    while(1)
    {
        sleep(1);
    }

    // 如果放在这里注册信号响应函数,也能捕捉到信号,但是会有意想不到的结果
    signal(34, func);  
    
    return 0;
}

        2、信号的屏蔽

// 信号的阻塞(屏蔽)操作示例

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

void func(int sig)
{
    printf("call func\n");
    printf("catch signal %d\n", sig);
}

int main(int argc, char *argv[])
{
    // 注册信号响应函数
    signal(34, func);
    printf("my pid is %d\n", getpid());

    // 设置信号阻塞,阻塞34号信号
    sigset_t set;
    sigemptyset(&set);  // 清空信号集
    sigaddset(&set, 34);    // 把34信号添加到信号集中
    
    if(sigprocmask(SIG_SETMASK, &set, NULL) == -1)  // 把信号集中的所有信号设置为阻塞
    {
        perror("设置阻塞失败\n");
    }

    sleep(10);   // 10秒内不会对34号进行处理

    if(sigprocmask(SIG_UNBLOCK, &set, NULL))   // 解除信号集中的阻塞信号
    {
        perror("设置阻塞失败\n");
    }

    while(1)
    {
        sleep(1);
    }



    return 0;
}

六、总结

        信号是进程间异步通信的方式,Linux系统下有62个信号,1~31号是标准信号,34~64是实时信号,对信号的响应方式有四种,分别是屏蔽(阻塞),捕捉,默认处理和忽略。注册信号响应函数的语句应该放在主函数体内前面。

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

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

相关文章

云服务器 宝塔(每次更新)

su root 输入密码 使用 root 权限 /etc/init.d/bt default 获取宝塔登录 位置和账号密码。进入宝塔 删除数据库 删除php前端站点 删除PM2后端项目 前端更改完配置打包dist文件 后端更改完配置项目打包 数据库结构导出 导入数据库 配置 PM2 后端 安装依赖

任务执行和调度----Spring线程池/Quartz

定时任务 在服务器中可能会有定时任务&#xff0c;但是不知道分布式系统下次会访问哪一个服务器&#xff0c;所以服务器中的任务就是相同的&#xff0c;这样会导致浪费。使用Quartz可以解决这个问题。 JDK线程池 RunWith(SpringRunner.class) SpringBootTest ContextConfi…

java开发之fastjson

依赖 <!-- fastjson依赖 --> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> <…

数据分析基础-数据可视化学习笔记04-互动方式

交互方式 交互&#xff08;Interaction&#xff09;是指用户与系统、设备或其他用户之间的相互作用、传递信息和交流的过程。在计算机科学、人机交互和用户体验领域&#xff0c;交互是用户与技术之间的核心概念&#xff0c;它决定了用户如何与计算机系统或其他技术进行沟通、操…

【项目 计网6】 4.17 TCP三次握手 4.18滑动窗口 4.19TCP四次挥手

文章目录 4.17 TCP三次握手4.18滑动窗口4.19TCP四次挥手 4.17 TCP三次握手 TCP 是一种面向连接的单播协议&#xff0c;在发送数据前&#xff0c;通信双方必须在彼此间建立一条连接。所谓的“连接”&#xff0c;其实是客户端和服务器的内存里保存的一份关于对方的信息&#xff…

基于Visual studio创建API项目

API&#xff08;英文全称&#xff1a;Application Programming Interface,中文&#xff1a;应用程序编程接口&#xff09; 为什么要 通过API接口可以与其他软件实现数据相互通信&#xff0c;API这项技术能够提高开发效率。 本文是基于vs2017 .net平台搭建API。希望可以帮助到学…

从2023年世界机器人大会发现机器人新趋势

机器人零部件为何成2023年世界机器人大会关注热门&#xff1f; 在原先&#xff0c;机器人的三大核心零部件是控制系统中的控制器、驱动系统中的伺服电机和机械系统中的精密减速器。如今&#xff0c;机器人的主体框架结构已经落实&#xff0c;更多机器人已经开始深入到各类场景中…

mysql Left Join on条件 where条件的用法区别

数据准备 SELECT t1.id,t1.name,t2.local FROM t1 LEFT JOIN t2 ON t1.idt2.id; 执行结果 SELECT t1.id,t1.name,t2.local FROM t1 LEFT JOIN t2 ON t1.idt2.id and t2.localbeijing; SELECT t1.id,t1.name,t2.local FROM t1 LEFT JOIN t2 ON t1.idt2.id where t2.localbeijing…

设计模式--建造者模式(Builder Pattern)

一、什么是建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它关注如何按照一定的步骤和规则创建复杂对象。建造者模式的主要目的是将一个复杂对象的构建过程与其表示分离&#xff0c;从而使同样的构建过程可以创建不同的表示。…

Kali 软件管理

kali 更新 1. 查看发行版本 ┌──(root㉿kali)-[~] └─# lsb_release -a No LSB modules are available. Distributor ID: Kali Description: Kali GNU/Linux Rolling Release: 2023.2 Codename: kali-rolling2. 查看内核版本 ┌──(root㉿kali)-[~] └─…

模拟实现库函数strcpy以及strlen

目录 strcpy 介绍库函数strcpy 例子 分析模拟实现思路 补充 assert宏 const关键字来修饰源字符串的指针 代码展示 strlen 介绍库函数strcpy 例子 分析模拟实现思路 计数器 递归 指针-指针 代码展示 计数器 递归 指针-指针 strcpy 介绍库函数strcpy 这个库函…

poi带表头多sheet导出

导出工具类 package com.hieasy.comm.core.excel;import com.hieasy.comm.core.excel.fragment.ExcelFragment; import com.hieasy.comm.core.utils.mine.MineDateUtil; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.*; import org.apache.po…

SpringCloud入门——微服务调用的方式 RestTemplate的使用 使用nacos的服务名初步(Ribbon负载均衡)

目录 引出微服务之间的调用几种调用方法spring提供的组件 RestTemplate的使用导入依赖生产者模块单个配置的情况多个配置的情况没加.yaml的报错【报错】两个同名配置【细节】 完整代码config配置主启动类controller层 消费者模块进行配置restTemplate配置类controller层 使用na…

【Java架构-版本控制】-Git进阶

本文摘要 Git作为版本控制工具&#xff0c;使用非常广泛&#xff0c;在此咱们由浅入深&#xff0c;分三篇文章&#xff08;Git基础、Git进阶、Gitlab搭那家&#xff09;来深入学习Git 文章目录 本文摘要1. Git分支管理2. Git分支本质2.1 分支流转流程(只新增文件)2.2 分支流转流…

[NLP]LLM--transformer模型的参数量

1. 前言 最近&#xff0c;OpenAI推出的ChatGPT展现出了卓越的性能&#xff0c;引发了大规模语言模型(Large Language Model, LLM)的研究热潮。大规模语言模型的“大”体现在两个方面&#xff1a;模型参数规模大&#xff0c;训练数据规模大。以GPT3为例&#xff0c;GPT3的参数量…

基于CentOS搭建私有仓库harbor

环境&#xff1a; 操作系统&#xff1a;CentOS Linux 7 (Core) 内核&#xff1a; Linux 3.10.0-1160.el7.x86_64 目录 安装搭建harbor &#xff08;1&#xff09;安装docker编排工具docker compose &#xff08;2&#xff09;下载Harbor 安装包 &#xff08;3&…

【C语言】程序环境预处理 -- 详解

一、程序的翻译环境和执行环境 在 ANSI C 的任何一种实现中&#xff0c;存在两个不同的环境。 翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。执行环境&#xff0c;它用于实际执行代码。 1、翻译环境 组成一个程序的每个源文件通过编译过程分别转换成目标代…

【AutoLayout案例04-游戏图片-按钮适配 Objective-C语言】

一、好,我们再看一个案例, 刚才,这个案例, 这么一个案例 这个案例,是什么意思呢, 这里给大家做一个3.5英寸、4.0英寸的屏幕适配, 因为我们这里图片,只有一个,就是4英寸的这么一个图片 什么意思呢,要求我们在3.5英寸的屏幕、和4英寸的屏幕的时候,都能正常显示这个图…

期权是什么?期权的优缺点是什么?

期权是一种合约&#xff0c;有看涨期权和看跌期权两种类型&#xff0c;也就是做多和做空两个方向&#xff0c;走势标的物对应大盘指数&#xff0c;这也是期权与其他金融工具的主要区别之一&#xff0c;可以用于套利&#xff0c;对冲股票和激进下跌的风险&#xff0c;下文介绍期…

LeetCode-56-合并区间

题目描述&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 可以使用 LinkedList&#xff0c;…