【Linux】IPC-信号

在这里插入图片描述

💻文章目录

  • 📄前言
  • 信号
    • 概念
    • 信号阻塞
      • 概念
    • 信号的处理
    • 信号的使用
  • 📓总结


📄前言

信号,一种无论是生活还是编程都离不开的东西。生活中,我们通过信号来对外部发生的事情进行反应,就好像你的手机来了一条信息,你可以选择点开处理它,也可以忽略掉它,而在Linux中的信号也是如此。

信号

概念

信号是Linux进程间通信的一种方式,主要用于进程接受异步事件的通知。你可以把信号看出是一种软件中断(软件触发的中断机制),进程通过接受信号来对响应外部的事情,例如程序异常、子进程结束、终端中按下中断键(Ctrl + C)都是会给进程传递信号。

Linux中信号分为两类: 标准信号与实时信号。

  • 标准信号:linux中的1-32号信号都是标准信号,信号被处理前,只能被存储一次。

  • 实时信号:指的是34号信号以上的信号,他们比标准信号更高级,可以使用队列来存储。

╭─ ~/.lcpr                                                           
╰─❯ kill -l	# 使用kill -l 来查看所有信号
HUP INT QUIT ILL TRAP IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS# 如果我们想要对某个进程发送信号,也是使用kill
kill 【you_process】 【signal】;# 当然,我们也有更简易的发送信号的方式
# 使用键盘(Ctrl + C)发送 INT 信号
# 使用(Ctrl + Z) 发送 STOP 信号
# 使用 (Ctrl + \)发送

信号阻塞

概念

当我们程序正在执行某些重要任务的时候,可以会因为用户的任性(Ctrl + C)而随意传来SIGINT信号来结束进程,为了不让程序收到这种事情的影响,linux信号机制设计了两个关键的标志位:阻塞位与未决位(2bit)。

信号工作原理:

  • 信号到达且阻塞位为0,系统则将未决位设为1,并执行信号处理函数,处理完成将未决位重新设置位0
  • 信号到达阻塞位为1,系统则将未决位设为1,信号处理等待状态,直到阻塞被取消,信号被处理。
+---------------------+
|      task_struct    |
+----------+----------+----------------------+
| Signal   | Block    | Pending  | Handler   |
+----------+----------+----------+-----------+
| SIGHUP   |    0     |    0     | SIG_DFL   |
| SIGINT   |    1     |    1     | SIG_IGN   |
| SIGQUIT  |    1     |    0     | handler   | --*
|   ...    |   ...    |   ...    |   ...     |   |
+----------+----------+----------+-----------+   ||*----------------------*|vvoid sighandler(int signo) {...}

信号阻塞函数的介绍:

// 涉及头文件 <signal.h>struct sigset_t;	// 信号的集合,用于阻塞、等待、检查信号int sigemptyset(sigset_t *set);	//置空set
int sigfillset(sigset_t *set);	//初始化set,将所有信号添加到set中int sigaddset(sigset_t *set, int signum);	//为set增加信号
int sigdelset(sigset_t *set, int signum);	//删除set中的信号int sigismember(const sigset_t *set, int signum);
// 检查set中是否加入了signumint sigprocmask(int how, const sigset_t* set, sigset_t* oset);	//用于设置堵塞信号
// HOW 有三种参数,SIG_BLOCK、SIG_UNBLOCK、SIG_SETMASK// SIG_BLOCK:将set指向的信号集中的信号添加到当前阻塞信号集中// SIG_UNBLOCK:从当前阻塞信号集中移除set指向的信号集中的信号// SIG_SETMASK:将当前阻塞信号集设置为set指向的信号集的确切副本int sigpending(sigset_t* set);	
//用于检查当前进程哪些信号是阻塞未处理的,set用于储存这些信号。

阻塞信号函数的简单使用:

void task()
{pid_t id = getpid();for (int i = 1; i <= 32; ++i){if (i == SIGSTOP && i == SIGKILL)	//SIGSTOP 和 SIGKILL 无法被阻塞。continue;kill(id, i);printf("kill %d %d\n", id, i);sleep(1);}exit(0);
}void test()
{sigset_t set;// sigemptyset(&set);	//将set信号集设为空// for (int i = 1; i <= 32; ++i)		//     sigaddset(&set, i);	// 一个个添加信号sigfillset(&set);		// 初始化:将所有信号填加sigprocmask(SIG_SETMASK, &set, nullptr);	// 将set中的信号全部设为阻塞pid_t id = fork();	if (id == 0)task();wait(nullptr);
}

信号的处理

信号的处理方式有三种:默认处理、忽略信号或捕捉信号(自定义处理)。大部分信号的默认成立方式都是终止进程,但程序可以通过捕获信号(自定义信号处理函数)。除此之外,我们也可以将信号设为阻塞状态,这样程序就无法接受到信号。

    +-----------+       +-----------+       +-------------+|           |       |           |       |             ||  Kernel   |  ---> |  Process  |  ---> |  Signal     || (System)  |       |           |       |  Handler    |+-----------+       +-----------+       +-------------+^  |                  |                    ||  |                  |                    ||  +---- 发送信号 ----->             自定义的处理函数|                                          |+------- 产生信号(如:Ctrl+C, 异常)---------+

在C语言中,可以使用 signal 函数与 sigaction 函数来设置处理函数。

信号处理函数的介绍:

void(*signal(int sig, void(*func)(int)))(int);
// 看到这个这个函数原型你可能会面露难色。 但其实在里面我们只需要认识两个参数就足够了。
// sig:需要捕获的信号     func:一个函数指针,指向你自定义的捕获函数。
// 而signal的返回值也是和func一个类型的函数指针int sigaction(int sig, const struct sigaction* act, struct sigaction* oldact);
// sig:需要处理的信号   
// act:指向对信号的处理方式
// oldact:用于保存信号先前的处理方式,可设为NULL// struct sigaction的结构
struct sigaction {void     (*sa_handler)(int);	//信号处理函数指针void     (*sa_sigaction)(int, siginfo_t *, void *);	// 另一个处理信号的函数,当sa_flags 设置了”SA_SIGINFO“的时候使用。sigset_t   sa_mask;	//在信号处理函数执行时,额外需要阻塞的信号int        sa_flags;	// 用于指定信号处理的各种选项与行为void     (*sa_restorer)(void);	// 通常不使用
};

信号的使用

void task()
{struct sigaction act;sigset_t set;sigemptyset(&set);	//将set设空sigfillset(&act.sa_mask);	//初始化sigprocmask(SIG_SETMASK, &act.sa_mask, nullptr);	//sa_mask信号集阻塞for (int i = 1; i <= 32; ++i){if (i == SIGSTOP || i == SIGKILL)continue;raise(i);	//使用raise来向本进程发送信号}sigpending(&set);for (int i = 32; i > 0; --i){if (sigismember(&set, i) == 0)	//检查信号是否未决std::cout << i << std::endl;}std::cout << std::endl;
}int main()
{signal(SIGCHLD, SIG_IGN);	//子进程结束时发送SIGCHLD信号,将它设为SIG_IGN可免除waitpid_t id = fork();if (id == 0){task();return 0;}return 0;
}

📓总结

本篇文章我们探索从信号的概念到阻塞和处理函数的应用,相信你对linux系统编程又有了一个新的了解吧。

📜博客主页:主页
📫我的专栏:C++
📱我的github:github

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

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

相关文章

20240304 json可以包含复杂数组(数组里面套数组)

欣赏一下我的思维&#xff0c;它会以漫画&#xff0c;表格&#xff0c;文字。。。各种各样的形式呈现 对于问题1问题2 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;易于人阅读和编写&#xff0c;同时也易于机器解析和生成。JSON本质上是一种文本…

WRF模型教程(ububtu系统)-WPS(WRF Pre-Processing System)概述

一、WPS简介 WRF 预处理系统 (WRF Pre-Processing System&#xff0c;WPS) &#xff0c;集成了基于Fortran和C编写的程序&#xff0c;这些程序主要用于处理输入到real.exe的数据。WPS主要有三个程序和一些辅助程序。 二、各程序介绍 主要的程序为geogrid.exe、ungrib.exe、met…

算法的基本概念和复杂度

目录 一. 算法的基本概念1.1 什么是算法1.2 算法的五个特性1.3 怎么才算好的算法 二. 算法的时间复杂度三. 算法的空间复杂度 \quad 一. 算法的基本概念 \quad \quad 1.1 什么是算法 算法可以用自然语言来描述, 也可以用伪代码和代码来描述 \quad 1.2 算法的五个特性 有穷性, 一…

鸿蒙视频播放的实现

文章目录 前言播放效果视频播放的实现总结 一、前言 现在市面上很多应用都跟视频有关&#xff0c;那么在鸿蒙系统上怎么来播放视频呢&#xff0c;今天就讲解视频播放控件&#xff0c;让你也能快速地进行视频播放功能开发。 最后呢&#xff0c;我会提供一个鸿蒙中涉及的主要…

elasticsearch篇:DSL查询语法

1.DSL查询文档 众所周知&#xff0c;elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1. DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出…

Pytest全局变量的使用详解

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 这里重新阐述下PageObject设计模式&#xff1a; PageObject设计模式是selenium自动化最成熟&…

Html+threejs数字孪生三维场景实现

程序示例精选 Htmlthreejs数字孪生三维场景实现 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Htmlthreejs数字孪生三维场景实现》编写代码&#xff0c;代码整洁&#xff0c;规则&#xf…

练习题手撕总结

基础篇 1.基础知识&#xff08;时间复杂度、空间复杂度等&#xff09; 2.线性表&#xff08;顺序表、单链表&#xff09; 3.双链表、循环链表 4.队列 5.栈 6.递归算法 7.树、二叉树&#xff08;递归、非递归遍历&#xff09; 8.二叉搜索树&#xff08;BST&#xff09; 9.二分查…

鸿蒙Next-Grid布局

鸿蒙中的Grid布局类似于前端中的栅格布局 4.0 Grid 文档中心 在Grid组件中只能放GridItem组件 Entry Component struct GridCase {build() {Grid() {GridItem() {GridCaseItem()}GridItem() {GridCaseItem()}GridItem() {GridCaseItem()}GridItem() {GridCaseItem()}}.width…

面试秒过!测试老司机揭秘写好简历的7个细节!

咱们上次说到&#xff08;详见《一位做过HR的测试老司机带你换工作&#xff0c;简历回复率飙升》&#xff09;选好了要投的公司&#xff0c;然后就是准备简历的问题了。简历是HR对候选人的第一印象&#xff0c;一个有经验的HR初筛一份2页A4纸的简历通常只有几十秒的时间&#x…

OpenCV(八)——基本线条操作

基本线条操作 OpenCV中提供了基本的线条的操作&#xff0c;包括画直线、画矩形、画圆形等。 &#xff08;1&#xff09;画直线&#xff0c;在OpenCV中利用line()画直线&#xff0c;形式为image_with_line cv2.line(image, start_point, end_point, color, thickness)。line(…

CodeTop day2

class Solution {public ListNode reverseKGroup(ListNode head, int k) {ListNode dummy new ListNode(0);//设置虚拟头节点dummy.next head;ListNode pre dummy;//让起始和结束的k个节点从类似虚拟节点的头节点出发ListNode end dummy;while(end.next!null){for (int i0;…