信号2笔记

 
系统有以下处理信号的组合:
1、不可靠的信号(捕鼠器)
如果先后出现两个SIGINT信号杀死了进程,那么意味着你的系统是不可靠的信号:处理函数必须每次都重置。

sa_flags的值为SA_RESETHAND,就是这种信号:在调用信号处理函数时,将信号的处理方式重置为SIG_DEL。所以

出现第二SIGINT信号,按默认方式终止了进程。

什么是捕鼠器:
           一个信号意味着什么具有破坏性的事情发生,并被捕获。当信号或老鼠被捕获后,信号处理函数或

捕鼠器就失效了。
在早期的版本中,信号处理函数在另一个方面也像捕鼠器:在每次捕获之后,都必须重新设置它们。但设置也需

要时间,在弹簧被触发和设置完成之间,就有可能有老鼠溜走了。这一脆弱的间隙使得原有信号处理不可靠,有

些人称此为“不可靠的信号”。

例:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        newhandler.sa_mask=blocked;
        newhandler.sa_flags=SA_RESETHAND;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}

运行结果:
[root@localhost ~]# ./a.out
^c^c
Type a message
Received signal 2 .. waiting
Leaving inthandler

[root@localhost ~]#
退出了进程

2、SIGY打断SIGX的信号处理函数。
就像是在工作时接到了一个电话,处理这个电话意味着放下当前的工作,拿起电话,与打电话的人交谈,挂起电

话,然后回去做放在一边的工作。
像下面的程序:
当接连按下ctrl-c和ctrl-\会看到程序先跳到inthandler,接着跳到quithandler,然后再回到inthandler,最后回

到主循环。

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

#define INPUTLEN 100

int main(void)
{
 void inthandler(int);
 void quithandler(int);
 char input[INPUTLEN];
 int nchars;

 signal(SIGINT,inthandler);
 signal(SIGQUIT,quithandler);
 
 do{
  printf("\nType a message\n");
  nchars=read(0,input,(INPUTLEN-1));
  if(nchars==-1)
   perror("read returned an error");
  else {
   input[nchars]='\0';
   printf("You typed:%s",input);
  }
 }while(strncmp(input,"quit",4)!=0);
}

void inthandler(int s)
{
 printf("Received signal %d .. waiting\n",s);
 sleep(2);
 printf("Leaving inthandler\n");
}

void quithandler(int s)
{
 printf("Received signal %d .. waiting\n",s);
 sleep(2);
 printf("Leaving quithandler\n");
}

运行结果:
[root@localhost ~]# ./a.out
^c^\
Type a message
Received signal 2 .. waiting
Received signal 3 .. waiting
Leaving quithandler
Leaving inthandler
光标在此,等待输入。

[root@localhost ~]# ./a.out
^c
Type a message
Received signal 2 .. waiting
^c Leaving inthandler          在调用信号处理函数inthandler内的2秒休眠时再发出一个SIGINT信号
Received signal 2 .. waiting
Leaving inthandler

结论:当调用一个信号处理程序时,被捕捉到的信号添加到进程的当前信号屏蔽字中,当从信号处理程序返回时

,恢复原来的屏蔽字,所以第二个SIGINT信号等到第一次信号处理程序返回主程序后再调用一次信号处理程序。

3、SIGX打断SIGX的信号处理函数
这种情况就像两个人来敲门,有3种处理的方法:
1)递归,调用同一个处理函数
sa_flags的值为SA_NODEFER是采用递归:当捕捉到多个此信号,某个此信号都会调用同一个信号处理程序,系统

不自动阻塞此信号。
例:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        newhandler.sa_mask=blocked;
        newhandler.sa_flags=SA_NODEFER;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}

运行结果:
[root@localhost ~]# ./a.out
^c^c^c
Type a message
Received signal 2 .. waiting
Received signal 2 .. waiting
Received signal 2 .. waiting
Leaving inthandler
Leaving inthandler
Leaving inthandler
read returned an error: Interrupted system call

Type a message
等待输入

并发现被中断的系统调用错误返回了,并不重新开始。

2)忽略第二个信号

3)阻塞第二个信号直到第一个处理完毕
sa_mask字段说明了一个信号集,在调用信号捕捉函数之前,这一信号集要加到进程的信号屏蔽中。仅当从信号

捕捉函数返回时再将进程的信号屏蔽字复位为原先值。
因此保证了在处理一个给定的信号时,如果这种信号再次发生,那么它会阻塞到对前一个信号的处理结束为止。

例1:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        sigaddset(&blocked,SIGINT);
        newhandler.sa_mask=blocked;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}
运行结果:
[root@localhost ~]# ./a.out
^c^c
Type a message
Received signal 2 .. waiting
Leaving inthandler
Received signal 2 .. waiting
Leaving inthandler
read returned an error: Interrupted system call

Type a message
等待输入

第一个ctrl-c,调用了信号处理函数,在调用前阻塞了SIGINT信号,此时再按下ctrl-c时,第二个信号被阻塞,

在第一个处理函数完毕,消除了对SIGINT的阻塞,然后再调用第二个信号处理函数

例2:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        sigaddset(&blocked,SIGQUIT);
        newhandler.sa_mask=blocked;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}

运行结果:
[root@localhost ~]# ./a.out
^c^\
Type a message
Received signal 2 .. waiting
Leaving inthandler
退出

如果以很快的速度连续按ctrl-c和ctrl-\,退出信号将被阻塞直到中断信号处理完毕,完毕后,退出信号按默认

动作终止进程。

4、被中断的系统调用
就像打电话时有人敲门,去开门,开好门后,拉起电话,将此电话已断了还是重新开始交谈。

程序经常在等待输入的时候收到信号,从信号处理函数返回后,是系统调用函数重新开始输入,还是系统调用函

数直接返回错误了?
sa_flags的值SA_RESTART:是系统调用重新开始而不是返回-1。
例:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        newhandler.sa_mask=blocked;
        newhandler.sa_flags=SA_RESTART;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}
运行结果:
[root@localhost ~]# ./a.out

Type a message
hel^cReceived signal 2 .. waiting
loLeaving inthandler

You typed:lo

Type a message
光标等待输入

这是输入"hel",接着按下ctrl-c然后再继续输入"lo"再回车的结果。

sa_flags的值SA_INTERRUPT:系统调用不重新开始而是返回-1,同时设置errno到EINTR。
例:
#include <stdio.h>
#include <signal.h>

#define INPUTLEN 100

int main(void)
{
        void inhandler(int);
        char input[INPUTLEN];
        int nchars;

        struct sigaction newhandler;
        sigset_t blocked;
        newhandler.sa_handler=inhandler;
        sigemptyset(&blocked);
        newhandler.sa_mask=blocked;
        newhandler.sa_flags=SA_INTERRUPT;
        sigaction(SIGINT,&newhandler,NULL);

        do{
                printf("\nType a message\n");
                nchars=read(0,input,(INPUTLEN-1));
                if(nchars==-1)
                        perror("read returned an error");
                else {
                        input[nchars]='\0';
                        printf("You typed:%s",input);
                }
        }while(strncmp(input,"quit",4)!=0);
}

void inhandler(int s)
{
        printf("Received signal %d .. waiting\n",s);
        sleep(2);
        printf("Leaving inthandler\n");
}
运行结果:
[root@localhost ~]# ./a.out

Type a message
helReceived signal 2 .. waiting
Leaving inthandler
read returned an error: Interrupted system call

Type a message
等待输入

这是输入"hel",接着按下ctrl-c,系统调用函数read返回-1,不重新开始

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值