Linux中的进程信号

Linux中进程的信号

我们在Linux的shell下启动一个前台进程,然后按下ctrl+c使进程中断,那有没有想过它的底层原理是什么?



一、进程信号是什么?

进程信号是一种“软件中断”,一种事件通知机制。通知进程发生了某个事件,打断进程当前操作,去处理这个事件。
查看信号种类:kill -l
在这里插入图片描述
每个信号表示一个事件,总共有62种信号,1-31号信号是借鉴Unix操作系统的非可靠信号(可能会信号丢失),34-64号是可靠信号。
在路径: /usr/include/bits/signum.h,查看这个头文件,这些信号都被定义为宏。在这里插入图片描述


二、信号的生命周期

产生——注册——注销——处理

1.信号产生

1.硬件产生: ctrl+c:发送SIGINT中断信号;

在这里插入图片描述
ctrl+\ :发送SOGQUIT退出信号;
在这里插入图片描述

ctrl+z:发送SIGSTOP停止信号

int main(int argc, char *argv[])
{
    while(1)
    {
        printf("_____________\n");
        sleep(1);
    }
    return 0;
}

该进程处于“T”状态,进程由前台进程变为后台进程,
jobs:查看后台停止作业;
fg 作业序号:将该后台停止作业转换到前台。
在这里插入图片描述
2.软件产生:
kill(命令):kill -signum pid 杀死一个进程,给进程发送一个信号-默认是终止信号(例如kill -9 就是发送SIGKILL信号),如果不指定信号,则发送默认信号SIGTERM;
kill函数(系统调用):int kill(pid_t pid, int sig);
参数解释:pid:指定要将信号发送给哪个进程;
sig:指定要发送的信号;
返回值:成功返回0,失败返回-1.

int main(int argc, char *argv[])
{
    kill(getpid(),SIGINT);
    while(1)
    {
        printf("_____________\n");
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
运行程序直接中断。
在这里插入图片描述
int raise(int sig):给调用进程自身发送指定信号。

unsigned int alarm(unsigned int seconds):设置一个定时器,多少seconds秒后,给进程发送一个SIGALRM信号(该信号默认处理方式为退出进程)。

int main(int argc, char *argv[])
{
    alarm(3);
    while(1)
    {
        printf("_____________\n");
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
void abort(void):给进程发送一个SIGABRT信号,abort函数使当前进程接收到信号而异常终止。


2.信号在进程中注册

在进程的pcb中有个未决信号集合(pending)-还没有被处理的信号的集合——位图,还有一个struct sigqueue专门存放信号信息节点的队列(双向链表)。
注册就是在未决信号集合中标记信号将0置为1,然后给双向链表中添加信号的信息节点。
非可靠信号:若信号已经注册,则不作任何操作;
可靠信号:无论信号是否注册,都会进行注册(置1加添加节点)。
在这里插入图片描述


3.信号注销

删除在进程pcb中的信号信息节点,重置位图为0。
非可靠信号:删除信息节点,直接位图置0;
可靠信号:删除信息节点之后,确定没有相同节点才会重置位图。


4.信号处理

执行信号的处理回调函数(sigaction-handler)。
在这里插入图片描述
如何修改信号的处理流程,暨修改处理函数?

1.sighandler_t signal(int signum, sighandler_t handler);
参数解释:
sigunm:信号值;
handler:信号要新指定的处理方式;
handler:SIG_DFL-默认;SIG_IGN-忽略;自定义函数
自定义函数的类型:typedef void (*sighandler_t)(int);
返回值:成功返回信号原来的处理方式,失败返回-1(SIG_ERR)。
举例忽略SIGINT,暨忽略ctrl+c:

int main(int argc, char *argv[])
{
    signal(SIGINT,SIG_IGN);
    while(1)
    {
        printf("_____________\n");
        sleep(1);
    }
    return 0;
}

在这里插入图片描述
自定义处理回调函数:
把SIGINT的处理方式改为打印信号值。

void sigcb(int signo)
{
    printf("recv signo : %d\n", signo);
}
int main(int argc, char *argv[])
{
    signal(SIGINT,sigcb);
    while(1)
    {
        printf("_____________\n");
        sleep(1);
    }
    return 0;
}

暨运行程序后按一次ctrl+c就会打印一次2.
在这里插入图片描述
注意:9号信号和19号信号不能被修改处理操作。

自定义处理方式的信号捕捉流程:
在这里插入图片描述
信号的处理是一种异步操作。

如何使程序运行从用户态切换到内核态:
中断、异常、系统调用


信号的阻塞

阻塞一个信号表示收到这个信号之后暂时不去处理,知道解除阻塞之后进行处理。
进程pcb中有一个信号阻塞集合,在这个集合中标记那个信号则阻塞哪个信号,
在这里插入图片描述
int sigprocmask(int how, const sigset_t * set, sigset_t * oldset);
参数解释:
how:要对信号阻塞集合进行的操作类型;
oldset:保存原有集合;
set:新集合;
①SIG_BLOCK:将set集合中的信号添加到阻塞集合中;block |= set;(block:101,set:010;——111)
②SIG_UNBLOCK:从阻塞集合中移除set集合中的信号;
③SIG_SETMASK:将set集合中的信号设置为阻塞集合的信号;block = set,覆盖式设置。
返回值:成功返回0,失败返回-1.

   #include <signal.h>

   int sigemptyset(sigset_t *set);清空set集合

   int sigfillset(sigset_t *set);将所有信号添加到set集合中

   int sigaddset(sigset_t *set, int signum);将指定信号添加到集合中

   int sigdelset(sigset_t *set, int signum);从集合中移除指定信号

   int sigismember(const sigset_t *set, int signum);判断信号是否在集合中

举个栗子:自定义修改两种信号(可靠和非可靠)signal。 先阻塞信号sigprocmask SIG_BLOCK,再使进程暂停getchar,暂停期间给进程发送信号,让进程继续运行,解除信号阻塞sigprocmask SIG_UNBLOCK。

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

void sigcb(int signo)
{
    printf("recv sino:%d\n", signo);
}
int main(int argc, char* argv[])
{
    signal(SIGINT, sigcb);//非可靠信号
    signal(40,sigcb);//可靠信号
    sigset_t set;
    sigemptyset(&set);
    sigfillset(&set);
    sigprocmask(SIG_BLOCK, &set,NULL);
    printf("回车解除暂停\n");
    getchar();
    sigprocmask(SIG_UNBLOCK,&set,NULL);
    while(1)
    {
        sleep(1); 
    }
    return 0;
}

在这里插入图片描述

  • 23
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值