当前位置: 首页 > news >正文

Liunx进程信号

进程信号

  • 进程信号
    • 什么是信号
    • liunx信号种类
  • 前后台进程
    • 前后台进程的概念
  • 进程信号的产生
    • 键盘产生
  • 阻塞信号
    • 信号的捕捉
      • 用户态和内核态
    • 信号的捕捉函数

进程信号

什么是信号

信号是Unix、类Unix以及其他POSIX兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。

liunx信号种类

Liunx中如何查看信号种类:
在这里插入图片描述

信号名称信号编号描述
SIGHUP1终端挂起或控制进程结束
SIGINT2终止进程(由键盘输入 Ctrl+C 产生)
SIGQUIT3终止进程并生成核心转储文件(由键盘输入 Ctrl+\ 产生)
SIGILL4非法指令
SIGTRAP5跟踪陷阱
SIGABRT6终止进程并生成核心转储文件(由调用 abort() 函数产生)
SIGBUS7非法地址访问
SIGFPE8浮点异常
SIGKILL9无条件终止进程
SIGUSR110用户定义的信号1
SIGSEGV11无效的内存引用
SIGUSR212用户定义的信号2
SIGPIPE13管道破裂
SIGALRM14定时器超时
SIGTERM15请求终止进程(默认终止信号)
SIGSTKFLT16协处理器栈错误
SIGCHLD17子进程状态改变
SIGCONT18继续被暂停的进程
SIGSTOP19停止进程
SIGTSTP20暂停进程(由键盘输入 Ctrl+Z 产生)
SIGTTIN21后台进程尝试读取控制终端
SIGTTOU22后台进程尝试写控制终端
SIGURG23套接字的紧急情况
SIGXCPU24CPU 时间限制超时
SIGXFSZ25文件大小限制超过
SIGVTALRM26虚拟定时器超时
SIGPROF27分析计时器超时
SIGWINCH28窗口大小调整
SIGIO29异步 I/O 事件
SIGPWR30电源故障
SIGSYS31非法系统调用

前后台进程

前后台进程的概念

前台进程在命令行操作时,只能有一个,后台进程可以有多个。

接下来我们启动一个后台进程。
我们创建一个后台进程,并且让他给文件不停的写入。
在这里插入图片描述
此时我们查看 log.txt
在这里插入图片描述
可以看到。进程在后台运行,那我们如何查看呢?
jobs 就可以看到
在这里插入图片描述
如何杀掉后台进程呢? 我们需要把fg后台放到前台,然后退出。
在这里插入图片描述
下面附上常用命令:

快捷键描述
Ctrl+C终止并退出前台进程,回到Shell
Ctrl+Z暂停前台命令执行,放到后台,回到Shell
jobs查看当前在后台执行的命令
&在后台执行命令
fg N将进程号码为N的命令放到前台执行
bg N将进程号码为N的命令放到后台执行

进程信号的产生

键盘产生

用户在Linux下执行一个前台进程,然后使用ctrl+c操作,会直接终止掉该前台进程。这是因为用户按下ctrl+c,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程,前台进程因为收到信号,进而引起进程退出。

ctrl+c组合键只能终止掉前台进程,对后台进程无效。这时我们可以使用kill -9指令来该终止进程
在这里插入图片描述
crtl+c的信号本质就是2号信合
在这里插入图片描述
接下来我们通过一个函数验证这个事:
在这里插入图片描述
在这里插入图片描述
像进程发送2号信合,运行新程序。
查看进程退出码:echo $?
在这里插入图片描述

························································································································································

阻塞信号

信号的常见分类:

  1. 实际执行信号的处理动作,称为信号递达(Delivery)。
  2. 信号从产生到递达之间的状态,称为信号未决(pending)。
  3. 进程可以选择阻塞(Block)某个信号。
    被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

需要注意的是,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后的一种处理动作。

在内核中的表示
未决信号,就是你的进程已经接收到了信号了,只是还没被信号处理函数处理的那些信号。

特别说明:虽然未决信号的定义是上面这样,但是这里我们需要更加具体一点,未决信号特指进程收到且被阻塞的信号。

在这里插入图片描述

  1. 每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。
  2. 在上图中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
  3. 在上图中,SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会在改变处理动作之后再接触阻塞。
  4. 在上图中,SIGQUIT信号未产生,正在被阻塞,不能执行自定义函数。
  5. 处理动作包括默认、忽略以及自定义。
    sigset_t
    根据信号在内核中的表示方法,每个信号的未决标志只有一个比特位,非0即1,如果不记录该信号产生了多少次,那么阻塞标志也只有一个比特位。

sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态。

在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞。 在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask)

信号集操作函数
sigset_t类型对于每种信号用一个bit表示“有效”或“无效”,至于这个类型内部如何存储这些bit则依赖于系统的实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的。

#include <signal.h>

int sigemptyset(sigset_t *set);// 对指定信号集进行清空。

int sigfillset(sigset_t *set);//对指定信号集进行置1

int sigaddset(sigset_t *set, int signum);//将指定的信号signum添加到信号集中 也就是置1

int sigdelset(sigset_t *set, int signum);//将指定的
信号signum在信号集中置0
int sigismember(const sigset_t *set, int signum); //判定signum是否为1 

接下来介绍重要函数:

#include<signal.h>
 int sigprocmask(int how,const sigset_t *set,__sigset_t *oset);
 //若返回成功则返回0.

how参数

选项含义
SIG_BLOCK设置包含了我们希望添加到当前信号屏蔽字的信号,相当于 `mask = mask
SIG_UNBLOCK设置包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于 mask = mask & ~set
SIG_SETMASK设置当前信号屏蔽字为 set 所指向的值,相当于 mask = set

接下来我们屏蔽2号信合!
在这里插入图片描述

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;

void handler(int signo)
{
    cout<<"handler get signo:"<<signo<<endl;
}

int main()
{
   signal(2,handler);
   //set==block oset== oblock
    sigset_t set,oset;

    sigemptyset(&set);//初始化
    sigemptyset(&oset);

sigaddset(&set,2);//设置对2号信合屏蔽 但是并没有设置进入系统

    sigprocmask(SIG_BLOCK,&set,&oset);
    while(1)
    {
        cout<<"mypid:"<<getpid()<<endl;
        sleep(1);
    }
    return 0;
}

#############################

设置完成后,我们对代码进行编译。

在这里插入图片描述

可以发现我对2号信合免疫了。

pending未决队列表的获取:

sigpending

读取当前进程的未决信号集,通过set参数传出来。


接下来我们以一个综合案例操作:

  1. 屏蔽2号信合 这个屏蔽是阻塞
  2. 通过sigpending查询2号信合
  3. 发送2号信合。
    在这里插入图片描述
    我们可以看到,发送2号信合,此时2号信合处于未决状态。
    在10次后,我们取消对2号的阻塞
    在这里插入图片描述

信号的捕捉

信号的捕捉发生在用户态和内核态的互相转换中,首选我们必须先知道什么是用户态,什么是内核态。

用户态和内核态

在这里插入图片描述

①OS在不在内存中被加载呢? ?——在 无论进程怎么切换,我们都可以找到内核的代码和数据,前提是你只要能够有权利访问!

②当前进程如何具备权利 访问这个内核页表乃至访问内核数据呢?——要进行身份切换。
进程如果是用户态的——>只能访问用户级页表 0~3G
进程如果是内核态的——>访问内核级和用户级的页表 3~4G 、③我怎么知道我是用户态的还是内核态的呢?
CPU内部有对应的状态寄存器CR3, CR3有比特位标识当前进程的状态 0:内核态,3:用户态

④0—>3
用户态切到内核态的情况:1.系统调用的时候。2.时间片到了,进程间切换。3.其他等等。执行完毕就继续切回用户态。即:程序运行从用户态切换到内核态的操作:中断/异常/系统调用,例如

    <1> 整数除以零操作会导致用户态—>内核态:因为会导致程序异常(分母不能为0)

    <2> sin()函数调用操作不会切换状态,因为库函数并不会引起运行态的切换

    <3> read 系统调用操作会导致用户态—>内核态:符合系统调用接口

⑤内核态vs用户态 内核态可以访问所有的代码和数据——内核态具备更高权限 用户态只能访问自己的

⑥我们的程序,会无数次直接或者间接的访问系统级软硬件资源(管理者是OS),本质上,你并没有自己去操作这些软硬件资源,而是必须通过OS-

无数次的陷入内核(1.切换身份3->0 2.切换页表,切到内核级页表)->调用内核的代码->完成访问的动作->结果返回给用户(1.切换身份0->3 2. 切换页表,切到用户级页表)->用户得到结果

⑦while(1);死循环进程普通程序会身份切换吗? —>也会陷入内核,来回切换身份 —>你也有自己的时间片
—>时间片到了的时候->OS收到中断信息,把进程从cpu移走,进程切到内核态,更换内核级页表 —>保护上下文,执行调度算法
—>选择了新的进程 —>恢复新进程的上下文 —>用户态,更换成用户级页表 —>CPU执行的就是新进程的代码!

重点: 用户态到内核态的两种切换场景:

  1. 除0错误。操作系统互捕捉这个错误,并且切换到内核态
  2. 使用系统调用函数接口,会从用户态切换到内核态。

自定义捕捉信号的处理过程
在这里插入图片描述
这个图是对自定义信号的处理,以及检测时机。

  1. 调用系统调用函数,此时用户态切换内核态
  2. 此时操作系统处理完之后,检测处理信号
  3. 信号为自定义信号处理方式 ,内核态不处理用户态代码
  4. 处理完成,继续返回内核态
  5. 从内核态返回用户态

在这里插入图片描述
正无穷记忆法!!!

信号的捕捉函数

  1. signal 常用捕捉函数
  2. sigaction 信号捕捉函数
int sigaction(int signum, const struct sigaction *act, struct sigaction *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:**这是一个指向函数的指针,当接收到指定的信号时,这个函数会被调用。如果设置为 SIG_IGN,则忽略该信号;如果设置为 SIG_DFL,则使用默认的信号处理行为。
**sa_mask:**这是一个信号集,用于在信号处理函数执行期间阻塞的信号。这确保了在处理一个信号时,不会受到其他信号的干扰。 也就是说,阻塞二号信号的
其他的几个参数并不需要我们了解。

相关文章:

  • Tuxera NTFS for Mac2023绿色免费版 免费的ntfs for mac 免费读写硬盘U盘工具
  • Linux存储的基本管理
  • 什么是Redis数据一致性?如何解决?
  • 操作系统① —— 进程管理
  • 单细胞RNA测序(scRNA-seq)SRA数据下载及fastq-dumq数据拆分
  • 设计模式:工厂模式和抽象工厂模式的区别
  • 每日面经分享(pytest测试案例,接口断言,多并发断言)
  • 第16章 网络编程
  • Oracle 数据库工作中常用知识点:sql语法与常用函数
  • 第五章 即速运用
  • AD20全流程的使用笔记
  • 【随笔】Git 高级篇 -- 相对引用2(十三)
  • 微信小程序怎么制作?制作一个微信小程序需要多少钱?
  • vue3表单参数校验+正则表达式
  • elsint报错Delete `␍`eslintprettier/prettier
  • python面试题(36~50)
  • 构建集创建、售卖、转让于一体,且基于ERC721 token的NFT平台,从编写智能合约开始(Web3项目四实战之一)
  • Property ‘startsWith‘ does not exist on type ‘string‘.
  • LabVIEW太赫兹波扫描成像系统
  • 数字化服务升级:数字乡村改善农民生活质量
  • 武汉大学新闻与传播学院已由“80后”副院长吴世文主持工作
  • 视频丨英伟达总裁黄仁勋:美勿幻想AI领域速胜中国
  • 从“长绳系日”特展看韩天衡求艺之路
  • 车展之战:国产狂飙、外资反扑、智驾变辅助
  • 国务院食安办:加强五一假期食品生产、销售、餐饮服务环节监管
  • “80后”蒋美华任辽宁阜新市副市长