进程信号

信号产生

1、终端产生        

SIGINT(2号信号)默认动作就是终止信号,SIGQUIT(3号)终止进程并且Core Dump(核心转储)

ctrl+c也就是给进程发2号信号

一个进程只有一个前台信号,可以由多个后天信号

ctrl+c给前台进程发信号,所以无法终止后台信号

Core Dump是什么?

当一个进程要异常终止时 , 可以选择把进程的用户空间内存数据全部 保存到磁
盘上 , 文件名通常是 core, 这叫做 Core Dump

进程退出时,status为位图中存放Core Dump的标志,1表示发生核心转储

2、调用系统函数向进程发信号

kill -l可以查看所有信号

kill给指定进程发信号,raise给自己发信号

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
abort让进程异常退出,并且产生core dump
#include <stdlib.h>
void abort(void);

3、由软件条件产生信号

SIGPIPE 是一种由软件条件产生的信号,进程向已经关闭的管道写入数据
alarm函数
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
设置一个闹钟,终止进程

4、硬件异常产生信号

硬件异常被硬件以某种方式检测到并通知内核,内核向当前进程发出适当信号

如下就是除0错误导致的CPU运算单元造成的异常,内核将这种异常解释为SIGFPE(8号信号)发送给进程

阻塞信号

信号常见的相关概念

信号递达:实际执行信号的处理动作

信号未决:信号产生与递达之间状态

进程可以选择阻塞信号

被阻塞的信号保持在未决状态,直到进程解除对此信号的阻塞,该信号才能够递达

信号处理

对信号的处理方式

1、忽略信号

2、执行信号默认处理动作

3、要求内核在处理信号时转换到用户态来处理,这种方式被称为信号捕捉(后面会提到)

信号在什么时候处理?
当进程从内核态返回用户态,进行信号检测处理

内核态:允许访问操作系统代码和数据

用户态:只能访问自己的代码和数据

信号在内核中

block和pending表是位图,handler是函数指针表

pending:1表示进程收到信号,0没有收到

block:1表示阻塞,0没有阻塞

handler:处理信号方式

pending什么时候从1变0?

执行信号捕捉方法之前,先变0,然后调用

sigset_t信号集表示对block和pending表做处理

sigset_t类型对于每种信号用一个比特位表示有效还是无效

信号集操作函数

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

sigemptyset函数初始化信号集set所有信号对应的比特位为0,表示信号集不包含任何信号

sigfiillset函数初始化信号集set所有信号对应的比特位为1,表示信号集包含所有信号

sigaddset函数使信号集signo信号对应的比特位变为1

sigdelset函数使信号集signo信号对应的比特位变为0

sigprocmask

读取或修改信号阻塞集合集

  • how 参数用于指定对信号屏蔽字的操作:
    • SIG_BLOCK:将 set 中指定的信号添加到当前信号屏蔽字中。
    • SIG_UNBLOCK:从当前信号屏蔽字中移除 set 中指定的信号。
    • SIG_SETMASK:用 set 中的信号集合替换当前的信号屏蔽字。
  • oldset 参数是一个指向 sigset_t 类型的指针,用于存储调用该函数之前的信号屏蔽字。
  • 返回值成功0,失败-1

sigpending

获取未决信号集

返回值成功0,失败-1

信号捕捉

sigaction函数

获取修改信号的处理方式

signum参数是要设置信号处理程序的信号的编号,可以是任何有效的信号编号,如 SIGINTSIGTERM 等。

struct sigaction只需要注意函数指针handler和sa_mask这两个就行

        handler:跟signal一样都是信号的处理方式

        sa_mask:阻塞信号集,执行期间阻塞其他信号,防止其它信号中断当前信号处理程序的执行。

oldset:储存之前信号处理方式

struct sigaction {
    void (*sa_handler)(int);           // 指向信号处理函数的指针
    void (*sa_sigaction)(int, siginfo_t *, void *);  // 用于指定信号处理函数的另一种形式,通常与 SA_SIGINFO 标志一起使用
    sigset_t sa_mask;                  // 用于阻塞的信号集合,即在执行信号处理函数期间要阻塞的其他信号
    int sa_flags;                      // 用于指定信号处理的标志
    void (*sa_restorer)(void);         // 废弃字段,在一些旧的系统中可能有作用
};

signal函数

两者之间的区别就在于sigaction更为灵活和安全,能够跟细致的对信号进行处理

volatile关键字

用来告诉编译器,变量的值可能会被程序之外的因素改变,因此编译器在优化时不能假设该变量的值不会突然改变。

volatile int flag=0;

void handler(int sig)
{
 printf("chage flag 0 to 1\n");
 flag = 1;
}
int main()
{
 signal(2, handler);
 while(!flag);
 printf("process quit normal\n");
 return 0;
}

 上述代码中如果没有volatile,那么while判断可能会被优化,flag变量可能直接被优化到CUP寄存器中 

这导致在收到信号2之后,handler函数处理时改变的flag,不会影响while判断中flag是0,所以出现如下情况

 加上volatile之后,就不会优化,保证外部因素可以改变flag

 

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-14 19:12:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-14 19:12:03       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-14 19:12:03       58 阅读
  4. Python语言-面向对象

    2024-07-14 19:12:03       69 阅读

热门阅读

  1. Android - 云游戏本地悬浮输入框实现

    2024-07-14 19:12:03       18 阅读
  2. SQL Server端口配置指南

    2024-07-14 19:12:03       22 阅读
  3. C#语言简介

    2024-07-14 19:12:03       27 阅读
  4. SQL多表查询

    2024-07-14 19:12:03       20 阅读
  5. 高通平台sensor初始化步骤

    2024-07-14 19:12:03       23 阅读
  6. pid内容索引

    2024-07-14 19:12:03       18 阅读
  7. C++ 异常

    2024-07-14 19:12:03       20 阅读