linux 信号原理 信号处理设置signal, 信号发送kill,信号等待sigsuspend,信号阻塞sigprocmask,一网打尽信号使用

news2024/9/20 22:02:02

专栏内容
postgresql内核源码分析
手写数据库toadb
并发编程
个人主页:我的主页
座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.

================================

概述

信号是一种软中断的方式,让进程陷入中断处理调用中;

linux 下信号也是一种进程间通信的手段;进程间也可以互相发送信号,来传递状态,让对方获知,并处理一些事情。

信号种类

linux下信号种类很多 ,可以通过kill 命令来查询

[senllang@localhost Dev]$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

这些信号分为两部分,

1-31 是POSIX定义的可靠信号,其中 SIGKILL,SIGSTOP 两个信号不能被应用程序捕获处理,不能被阻塞,也不能忽略。

34-64 是POSIX定义的real-time使用的信号,因为实时性,可能会丢失,主要有RTMAX, RTMIN两类;

信号处理函数

大多数信号可以被应用程序捕获,这样就可以设置处理函数自定义处理行为。

信号的处理函数,一般有三种:

  • 自定义,通过设置函数进行设置,当信号产生时调用此回调函数;
  • SIG_DFL ,默认值,执行默认行为;
  • SIG_IGN ,忽略,不执行任何动作;

信号处理函数设置

自定义信号的处理函数, 设置处理函数有两个函数signal和sigaction ,它们定义如下:

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

这个函数相对简单,signum 就是要处理的信号值,handler就是自定义处理函数,类型必须是 sighandler_t;
让我们举个例子看一下。

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

void MySigproc(int signumber)
{
  printf("catch signal is %d, we process it now.\n",signumber);
}

int main()
{
  signal(2,MySigproc);
  signal(3,MySigproc);
  signal(10,MySigproc);
  signal(12,MySigproc);

  do
  {
    /* code */
    sleep(1000);
    printf("signal break me dream.\n");
  } while (1);
  
  return 0;
}

获后我们来运行一下,看下效果

# 终端 1 运行 
[senllang@localhost signal]$ ./a.out
# 终端 2 发送信号  
[senllang@localhost Dev]$ ps -ef|grep a.out
senllang 2700150 2035891  0 14:41 pts/1    00:00:00 ./a.out
senllang 2700164 2119038  0 14:41 pts/4    00:00:00 grep --color=auto a.out
[senllang@localhost Dev]$ kill -2 2700150
[senllang@localhost Dev]$ kill -3 2700150
[senllang@localhost Dev]$ kill -10 2700150
[senllang@localhost Dev]$ kill -12 2700150
# 终端 1 捕获信号  
catch signal is 2, we process it now.
signal break me dream.
catch signal is 3, we process it now.
signal break me dream.
catch signal is 10, we process it now.
signal break me dream.
catch signal is 12, we process it now.
signal break me dream.

最后按下Ctr+c已经不起作用了,最后用kill -9 强制结束

另外设置函数提供的选项比较丰富,通过传入sigaction结构体参数来设置

#include <signal.h>

int sigaction(int signum,
              const struct sigaction *_Nullable restrict act,
              struct sigaction *_Nullable restrict oldact);

struct sigaction 
{
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t   sa_mask;
    int        sa_flags;
    void     (*sa_restorer)(void);
};              
  • 其中 sa_handler 和 sa_sigaction 设置其一就可以;
  • sa_handler 可以设置三种处理方式,默认,忽略,自定义
  • sa_restorer 不是给应用程序使用的,不用管;
  • sa_mask 是设置那些信号位被阻塞,可以|多个信号;
  • sa_flags 是定义一些行为;

信号阻塞

信号阻塞,在设置信号阻塞掩码sigmask, 置1的信号在产生后,处于pending状态,即信号未决状态,
直到信号投递,也就是信号处理函数被调用。

接口说明

sigprocmask 接口可以获取 或者 设置 信号mask

#include <signal.h>

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

参数说明

  • how 可以为
  • SIG_BLOCK, set 中的信号为要阻塞的信号,加到已有的阻塞信号中
  • SIG_UNBLOCK, set 中的信号为要解除阻塞的信号,从已有的阻塞信号中去除
  • SIG_SETMASK, 将现有的阻塞信号替换为 set 指定的信号
  • set , 要修改的信号集

  • oldset, 不为空,获取修改前的信号集

多线程时,要用 pthread_sigmask ,功能一样

下面举例,先将所有信号阻塞,然后再将SIGINT信号解除阻塞

void blocksig()
{
  sigset_t set;
  sigset_t oldset;

  sigfillset(&set);//所有比特位全部置为1,则信号会全部被阻塞
  sigprocmask(SIG_BLOCK,&set,&oldset);

  sigemptyset(&set);//初始化信号量集
  sigaddset(&set, SIGINT);//将SIGINT添加到信号量集中
  sigprocmask(SIG_UNBLOCK, &set, &oldset);
}

信号产生

信号可以是命令产生,如键盘按键,或kill 等;

也可以由程序控制,来给某个进程发送信号。

发送信号

可以通过这些函数进行信号发送

  • raise 发送一个信号给调用线程
#include <signal.h>
int raise(int sig);
  • kill 发送信号给指定pid的进程,或者进程组,或者所有进程
#include <signal.h>
int kill(pid_t pid, int sig);
  • 还有其它的,如 pidfd_send_signal, killpg, pthread_kill,tgkill, sigqueue等,用到时可以再研究。

等待信号

就是当前进程被阻塞,直到某个信号发生;
当信号处理函数返回时,当前阻塞的进程才继续运行

#include <unistd.h>
int pause(void);

#include <signal.h>
int sigsuspend(const sigset_t *mask);

我们举个例子来看看

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

void MySigproc(int signumber)
{
  printf("catch signal is %d, we process it now.\n",signumber);
}

int main()
{
  sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGQUIT);
    sigaddset(&set, SIGUSR1);

    signal(SIGINT,MySigproc);
  signal(SIGQUIT,MySigproc);
  signal(SIGUSR1,MySigproc);
  signal(SIGUSR2,MySigproc);

  do
  {
    /* code */
    sigsuspend(&set);
    printf("signal break me dream.\n");
  } while (1);
  
  return 0;
}

通过两个终端进行演示

# 终端1 运行结果 
[senllang@localhost signal]$ ./a.out
catch signal is 12, we process it now.
catch signal is 10, we process it now.
catch signal is 3, we process it now.
catch signal is 2, we process it now.
signal break me dream.

# 终端2 发送信号 
[senllang@localhost Dev]$ ps -ef|grep a.out
senllang 2723802 2035891  0 19:28 pts/1    00:00:00 ./a.out
senllang 2723806 2119038  0 19:28 pts/4    00:00:00 grep --color=auto a.out
[senllang@localhost Dev]$ kill -2 2723802
[senllang@localhost Dev]$ kill -3 2723802
[senllang@localhost Dev]$ kill -3 2723802
[senllang@localhost Dev]$
[senllang@localhost Dev]$ kill -10 2723802
[senllang@localhost Dev]$ kill -12 2723802

我们看到,在终端2不断发送信号,直到发送了等待的非挂起信号12后,才开始解除信号阻塞,并处理消息,并解除进程阻塞
对于2,3,10是阻塞信号,并没有立即处理,而且阻塞信号只处理一次

进阶内容

信号处理函数的注意事项

  • 处理函数是可重入的
  • 处理函数不是被应用程序调用,而是有自己独立的栈;

保护临界区

当在关键代码段时,我们不希望被中断,不被干扰,在之前或之后再处理中断。

一般会在关键代码块前阻塞信号,然后执行完关键代码块后获取未决的信号进行处理;

常见软件信号

  • 程序内部错误, 如除0,访问非法内存等;一般是abort , signal 6 SIGABRT信号;
  • 在终端运行程序时,按下Ctrl+c时,程序强制退出,产生的是SIGINT信号,如果没有指定处理函数,默认就是退出程序;

子进程继承

  • 当通过 fork 生成的子进程,会继承父进程的信号设置和处理函数;
  • 当通过 execv 产生的子进程,会重置信号设置;

进程与线程的信号

  • 进程可以设置信号阻塞,线程同样也可以,每个线程是独立设置
  • 进程可以直接处理信号;由kill 或 sigqueue 产生的信号,指定了对应的pid ;
  • 线程也可以直接处理信号; tgkill 或 pthread_kill 产生的信号,指定了tid ;

结尾

非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!

作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。

注:未经同意,不得转载!

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

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

相关文章

vector的resver和resize

#include <iostream> #include <vector> using namespace std; int main() {std::vector<std::vector<std::vector<int> > > a(2);//创建2个vector<vector<int> >类型的数组vector<int> vec;//vec.resize(10); //结果1vec.res…

【Linux之拿捏信号3】阻塞信号

文章目录 相关概念原理sigset_t信号集信号集操作函数sigprocmask系统调用sigpending 相关概念 实际执行信号的处理动作——信号递达Delivery&#xff08;例如自定义捕捉动作&#xff0c;core&#xff0c;Term终止进程的动作&#xff09;。信号从产生到递达之间的状态——信号未…

Verilog基础之十四、FIFO实现

目录 一、FIFO 1.1 定义 1.2 实现方式 1.3 实现原理 二、代码实现 三、仿真结果 3.1 复位阶段 3.2 写入阶段 3.3 读取阶段 3.4 同时读写或不读不写 四、参考资料 一、FIFO 1.1 定义 FIFO(First in First out)为先进先出队列&#xff0c;具有存储功能&#xff0c;…

一篇带你彻底搞懂线程池

目录 一、自定义线程池 1、产生背景 2、堵塞队列 3、线程池 4、拒绝策略 二、ThreadPoolExecuor 1、线程池状态 2、构造方法 3、newFixedThreadPool 4、newCachedThreadPool 5、newSingleThreadExecutor 6、提交任务 7、关闭线程池 三、异步模式之工作线程 1、定…

C-数据的储存(上)

文章目录 前言&#x1f31f;一、数据类型详细介绍&#x1f30f;1.内置类型&#x1f4ab;&#xff08;1&#xff09;.整形家族&#x1f4ab;&#xff08;2&#xff09;.浮点数家族&#x1f30f;2.构造类型&#xff08;也称自定义类型&#xff09;&#x1f30f;3.指针类型&#x…

OpenCV 入门教程:Haar特征分类器

OpenCV 入门教程&#xff1a; Haar 特征分类器 导语一、Haar特征分类器原理二、Haar特征分类器步骤三、示例应用总结 导语 Haar 特征分类器是图像处理中常用的目标检测算法&#xff0c;用于识别图像中的特定目标。该算法基于 Haar-like 特征模板&#xff0c;通过训练分类器来实…

ArcGIS PRO基础教程(一)

操作要求 1.面积为50-80亩 2.不能选在有耕地、园地内 3.坡度小于15度,高程在以下1930 4.距离水源地在300米以内 已知数据 1.等高线图 CONTOUR 2.土地利用图 parcel 3.水系图 water 操作步骤 创建工程,模板选地图就可以了(注:在arcgis pro中创建工程可以看作在arcg…

大火的ChatGPT与表格插件结合会有哪些意想不到的效果?

大火的ChatGPT与表格插件结合会有哪些意想不到的效果&#xff1f; 摘要&#xff1a;本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 ChatGPT已经火了好…

前端全集Ⅰ---- HTML/CSS/JavaScript

一 介绍web开发 Web&#xff1a;全球广域网&#xff0c;也称万维网&#xff0c;能够通过浏览器访问的网站 Web网站的工作流程&#xff1a;&#xff08;前后端分离模式&#xff09; 网页有哪些组成&#xff1f; 文字、图片、视频、音频、超链接 前端代码通过浏览器的解析和渲…

3-exercises

解&#xff1a; &#xff08;1&#xff09;Create a tensor a from list(range(9)). Predict and then check the size, offset, and stride. 创建列表a 将其转化为张量 a.size&#xff1a;The size (or shape, in NumPy parlance) is a tuple indicating how many elements a…

脚本引流是什么?其实很好理解,就是利用软件脚本来引流,这种软件我们通常叫引流脚本

脚本引流是什么&#xff1f;其实很好理解&#xff0c;就是利用脚本来引流&#xff0c;这种软件我们通常叫引流脚本&#xff0c;引流脚本的研发就是结合了以往的那些加人软件&#xff0c;从中吸取了长处并且升级了功能&#xff0c;而且通过不断的测试改进&#xff0c;在今年的7月…

C# PaddleInference OCR文字识别(只识别)

说明 C# PaddleInference OCR文字识别&#xff08;只识别&#xff09;&#xff0c;没有文字区域检测、文字方向判断 测试图片是文字区域检测裁剪出来、处理过的图片 完整的OCR识别查看 C# PaddleInference OCR识别 学习研究Demo_天天代码码天天的博客-CSDN博客 效果 项目 …

-1在内存中的存储及打印问题。

首先先看看代码&#xff1a; #include"stdio.h" int main() { char a -1; signed char b -1; unsigned char c -1; printf("a%d b%d c%d", a, b, c); return 0; } 代码很简单&#xff0c;问打印结果是什么&#xff1f; 下面我…

Java 比对两张图片的差异

1.基本介绍 Github上的“https://github.com/akullpp/awesome-java”页整理了非常多的各类Java组件的实现&#xff0c;前面一篇从它的图片处理篇找到了《image-comparison》进行了动手实践&#xff0c;关于图片处理的二维码组件《ZXing》本站曾有实践&#xff1b;关于图片识别…

CUDA+CUDNN+torch+torchvision安装

弄了好久&#xff0c;终于弄好了&#xff01;&#xff01;&#xff01; 原因&#xff1a;其实之前我是已经配置好pytorch的相关环境的了。但是这段时间&#xff0c;在跑GNN相关论文中的代码时&#xff0c;发现代码中的某个函数要求torch必须得是1.8 而我之前安装的是torch1.1…

leetcode-209.长度最小的子数组

leetcode-209.长度最小的子数组 文章目录 leetcode-209.长度最小的子数组题目描述代码提交(快慢指针-滑动窗口) 题目描述 代码提交(快慢指针-滑动窗口) 代码 class Solution {public:int minSubArrayLen(int target, vector<int> &nums) {int slow 0;int fast 0;i…

Spring中事务传播机制的理解与简单试用

目录 一&#xff0c;前言 二&#xff0c;Spring框架中的事务传播行为 三&#xff0c;事务的传播行为测试 Propagation.REQUIRED Propagation.SUPPORTS Propagation.MANDATORY Propagation.REQUIRES_NEW Propagation.NOT_SUPPORTED Propagation.NEVER Propagation.NES…

c++11 标准模板(STL)(std::basic_istream)(三)

定义于头文件 <istream> template< class CharT, class Traits std::char_traits<CharT> > class basic_istream : virtual public std::basic_ios<CharT, Traits> 类模板 basic_istream 提供字符流上的高层输入支持。受支持操作包含带格式的…

从零配置 linux 开发环境

文章目录 目的效果图配置本地 Windows 主机好用工具WSLSSH 连接远程 Linux 开发机配置本机字体【in-prog】配置 vscode 远程连接 配置远程 Linux 主机zsh & oh-my-zsh配置 github 的 SSHneovimvundleinit.vim 文件 vim-plug.lua 文件 tmuxclangcpplint 目的 记录下我的开发…

Go语言开发者的Apache Arrow使用指南:高级数据结构

经过对前面两篇文章《Arrow数据类型》[1]和《Arrow Go实现的内存管理》[2]的学习&#xff0c;我们知道了各种Arrow array type以及它们在内存中的layout&#xff0c;我们了解了Go arrow实现在内存管理上的一些机制和使用原则。 Arrow的array type只是一个定长的、同类型的值序列…