Linux进程信号——信号处理

阻塞信号:

一、信号相关概念

1.实际执行信号的处理动作称为信号递达(Delivery).

2.信号从产生到递达之间的状态称为信号未决(Pending)。(不一定会立即Delivery)

3.进程可以选择阻塞(Block)某个信号。(不会递达)

4.被阻塞的信号产生时将保持在未决状态,知道进程解除对此信号 的阻塞,才会执行递达。

5.阻塞和忽略时不同的,信号被阻塞就不会递达,忽略是在递达之后,可选的一种处理动作。

二、在内核中的表示


该图中,每一行代表着一种信号,每一个进程PCB中都有一个信号的指针,分别由3个表控制一个信号,

1.block位图:表示每种信号是否被阻塞,0表示没有被阻塞,1表示被阻塞。

2.pending位图:表示每种信号的未决状态,1表示该信号已经已经产生,但还未递达。0表示信号没有产生,或者产生后已经递达了,此时该标志位也变为0。

扫描二维码关注公众号,回复: 1108323 查看本文章

3.handler表:实际是一函数指针数组,数组每个元素对应处理该信号的函数指针。如果是SIG_DEL表示自行默认处理动作,如果是SIG_IGN表示忽略该信号,如果是用户自定义处理动作,则保存的是自定义函数的指针。

所以,发送信号就可以描述为:操作系统修改进程PCB中pending表中将0变为1.

三、信号集与操作函数

1.sigset_t:未决和阻塞标志可以用相同的数据类型sigset_t来存储。这个类型可以表示每个信号有效或者无效状态。在阻塞信号中有效、无效代表着是否被阻塞,未决也是同样额,同时,阻塞信号集也称为当前进程的信号屏蔽字。

2.信号集操作函数:

#include<signal.h>

int sigemptyset(sigset_t* set);

该函数的功能是使set所指向的信号集变量的所有比特位清零,比如set所指向的是当前进程的阻塞信号集,所以在该进程中的所有信号都处于未屏蔽状态。

int sigfillset(sigset_t* set);  

  该函数的功能是使set所指向的信号集变量的所有比特位均变为1。比如set所指向的是当前进程的阻塞信号集,所以在该进程中的所有信号都处于屏蔽状态。

int sigaddset(sigset_t *set,int signo);  

该函数的作用是在set所指向的信号集中使signo信号变为有效信号。

int sigdelset(sigset_t* set,int signo);  

        该函数的作用是在set所指向的信号集中使signo信号变为无效信号。

int sigismember(const sigset_t* set,int signo);  

        该函数的作用是判断set所指向的信号集中signo信号是否有效。

以上都是成功返回0,失败返回-1。

四、sigprocmask

调用函数sigpromask可以读取进程或者更改进程的信号屏蔽字。

int sigprocmask(int how,const sigset_t* set,sigset_t* oset);  

参数:

    oset:如果该参数非空,相当于保存该进程原本的信号屏蔽字。

    set:如果该参数非空,则将根据how和set修改该进程的信号屏蔽字

  how:有以下三种

  SIG_BLOCK:此时set中包含的是我们希望添加到当前信号屏蔽字中的信号,相当于mask = mask|set

  SIG_UNBLOCK:此时set中包含的是我们希望从当前信号屏蔽字中解除的信号,相当于mask = mask&~set

  SIG_SETMASK:设置当前信号屏蔽字为set所指向的值,即mask = set。

返回值:成功返回0,失败返回-1

五、sigpending

        sigprocmask告诉我们如何对阻塞信号字进行读取和修改,那sigpending将会使我们读取进程的未决信号集。

int sigpending(sigset_t* set);  

读取进程的未决信号集,通过set参数传出。成功为0,失败-1.

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

void printfsigset(sigset_t *set)
{
    int i = 0;
    for (;i<32;++i)
    {
       if (sigismember(set,i))//判断信号是否在目标集合中
        {
            putchar('1');
        }
        else
        {
            putchar('0');
        }
    }
    printf("\n");
}

int main()
{
    sigset_t s,p;
    sigemptyset(&s);//定义信号集,并清空初始化
    sigaddset(&s,SIGINT);//Ctrl+c
    sigprocmask(SIG_BLOCK,&s,NULL);//阻塞SIGINT信号
    while(1)
    {
        sigpending(&p);//获取未决信号集
        printfsigset(&p);
        sleep(1);
    }
    return 0;
}

如果执行了这个代码,发现用Ctrl+c 不能发送信号退出进程,想要退出的话,找到这个进程的pid,kill掉就行。





猜你喜欢

转载自blog.csdn.net/duckyloser/article/details/79994544