Linux基础篇——信号

Linux下的信号列表
这里写图片描述
列表中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的),编号为32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号)。不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

信号的产生方式有四种:
1、硬件中断
2、命令行(指令)
3、函数调用
4、软件条件(程序异常)
信号的处理动作有三种:
1、忽略此信号
2、执行该信号的默认处理动作(一般为结束该进程)
3、执行一个信号处理函数,要求内核在处理此信号时切换到用户态执行(称为捕捉一个信号)

自定义信号处理函数
代码如下:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void Fun()
{
    sleep(1);
    printf("hello zhangwei\n");
}
int main()
{
    signal(SIGINT,Fun);
    while(1)
    {}
    return 0;
}

执行情况如下:
这里写图片描述

产生信号详解

1、通过终端按键产生信号
core文件
在SIGINT的默认处理动作是要终止进程,SIGQUIT的默认动作是终止进程并Core Dump,当⼀一个进程要异常终⽌止时,可以选择把进程的⽤用户空间内存数据全部 保存到磁盘上,⽂文件名通常是core,这叫做Core Dump。进程异常终⽌止通常是因为有Bug,⽐比如⾮非法内存访问导致段错误,事后可以⽤用调试器检查core⽂文件以查清错误原因,这叫做Post-mortem Debug(事后调试)。⼀一个进程允许产⽣生多⼤大的core⽂文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产⽣生core⽂文件的,因为core⽂文件中可能包含⽤用户密码等敏感信息,不安全。在开发调试阶段可以⽤用ulimit命令变这个限制,允许产⽣生core⽂文件。
core文件大小默认是0,所以不设置的话不会生成core文件
这里写图片描述
core文件最大可以为1024Kb,我们通过ulimit -c 1024命令设置core文件大小
在死循环程序中我们按下ctrl+’c’或ctrl+’\’,终止该进程,此时生成core文件,
这里写图片描述
2、通过系统函数向进程发信号
(1) kill命令是调用kill函数实现的,kill函数可以给一个指定的进程发特定的信号。
kill -信号标志 进程标号
函数原型

#include<signal.h>
 int kill(pid_t pid,int signo);
 int raise(int signo);

raise函数可以给当前进程发送指定的信号
(2) abort函数使当前进程接收到信号异常终止
函数原型 void abort(void);//和exit 函数一样,abort函数总是会成功的,所以没有返回值
3、由软件条件产生信号

#include<unistd.h>
unsigned in alarm(insigned int seconds);

函数原型如上,调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒后向进程发送一个SIGALRM信号

  1 #include<stdio.h>
  2 #include<signal.h>
  3 #include<unistd.h>
  4 
  5 int main()
  6 {
  7     int count=0;
  8     alarm(1);
  9     for(;1;count++)
 10     {
 11         printf("count = %d\n",count);
 12     }
 13     return 0;
 14 }

执行结果为1s中计算机计数次数
这里写图片描述

阻塞信号以及相关函数

几个概念:
实际执行信号的处理动作称为信号递达(Delivery)。
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞(Block )某个信号。被阻塞的信号产⽣生时将保持在未决状态,直到进程解除对此信号的阻塞,才 执行递达的动作。
,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后 可选的一种处理动作。
信号在内核中的表示示意图
这里写图片描述
每个信号都有两个标志位分别表⽰示阻塞(block)和未决(pending),还有⼀一个函数指针表⽰示处理
动作。信号产⽣生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标
志。在上图的例⼦子中,
1. SIGHUP信号未阻塞也未产生过,当它递达时执⾏行默认处理动作。
2. SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没 有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
3. SIGQUIT信号未产生过,⼀一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。

信号集操作函数

sigset_t类型对于每种信号用一个bit表⽰示“有效”或“无效”状态,至于这个类型内部如何存储这 些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操 作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 sigismenber(cosnt sigset_t *set,int signo);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。注意,在使用sigset_t类型的变量之前,一定要调 ⽤用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以 在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种 信号,若包含则返回1,不包含则返回0,出错返回-1。
sigprocmask
int sigprocmask(int how,const sigset_t *set,sigset_t *oset)
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)
返回值:若成功则为0,若出错则为-1
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指⽰示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
这里写图片描述
如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则sigprocmask返回前,⾄至少将其中 一个信号递达。

sigpending
int sigpending(sigset_t *set)
sigpending**读取当前进程的未决信号集**,通过set参数传出。调用成功则返回0,出错则返回-1。
下面通过程序来演示函数的功能

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

void printsigset(sigset_t *set)
{
    int i=1;
    for(;i<32;i++)
    {
        if(sigismember(set,i))
        {
            putchar('1');
        }
        else
        {
            putchar('0');
        }
    }
    printf("\n");
}


int main()
{
    sigset_t s,p;
    sigemptyset(&s);
    sigemptyset(&p);
    sigaddset(&s,SIGINT);
    sigprocmask(SIG_BLOCK,&s,&p);
    while(1)
    {
        sigpending(&p);
        printsigset(&p);
        sleep(1);
    }
    return 0;
}

执行结果如下:
这里写图片描述
我们可以发现,在没有按下ctrl+‘c’时,当前进程中未决信号集一直为0,在按下后,第二位变成了1。因为在按下ctrl+’c’时信号被阻塞,一直处于未决状态。
我们将代码修改如下:
修改while循环

       while(1)
    {
        sigpending(&p);
        printsigset(&p);
        ifcount&4==0)
        {
            sigprocmask(SIG_UNBLOCK,&s,NULL);
        }
        count++;
        sleep(1);
    } 

运行结果如下:
这里写图片描述
当ctrl+‘c’按下且if语句执行后,进程退出,因为此时信号已经为未决状态且未阻塞,所以执行默认动作,终止进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值