signal讲解

来源:互联网 发布:ubuntu 64位镜像下载 编辑:程序博客网 时间:2024/05/18 01:07

signal

#include<signal.h>

#include<sys/types.h>

int kill(pid_t pid,int sig)

pid的取值:

正数:要发送信号的进程号

0:信号被发送到所有和 pid 进程在同一个进程组的进程

1:信号发给所有的进程表中的进程(除了进程号最大的进程外)

int raise(int sig) 进程向自身发送信号

 

#include <unistd.h>

unsigned int alarm(unsigned int seconds)

alarm当定时器指定的时间到时, 它就向进程发送 SIGALARM 信号。

int pause(void)

挂起进程直到有信号到来,且当信号处理函数返回后pause()才返回-1。

unsigned int sleep(unsigned int seconds);

休息seconds秒后返回;或者被信号中断且信号处理函数返回后sleep()返回0。

所以如果不计较返回值的话,pause()的功能相当于无限期的sleep()。

最简单的函数如:

int main(){

  int ret=alarm(5);

  pause();

  printf(“I have been waken up.\n”);

}

可靠信号(实时信号)和不可靠信号(非实时信号):

一个不可靠信号的处理过程是这样的:如果发现该信号已经在进程中注册,那么就忽略该信号。因此,若前一个信号还未注销又产生了相同的信号就会产生信号丢失。而当可靠信号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次,因此信号就不会丢失。所有可靠信号都支持排队,而不可靠信号则都不支持排队。

signal()主要用于非实时信号的处理,不支持信号传递信息。

sigaction()可用于实时信号处理,支持信号传递消息。

信号处理函数必须是返回void,有且只有一个int参数。

复制代码
#include<stdio.h>#include<stdlib.h>#include<signal.h> /*自定义信号处理函数 */void foo(int sig_no)        //必须是返回void,有且只有一个int参数{    if (sig_no == SIGINT)    //按下Ctrl+C产生SIGINT信号        printf("I have got SIGINT\n");    if (sig_no == SIGQUIT)    //按下Ctrl+\产生SIGQUIT信号        printf("I have got SIGQUIT\n");}int main(){    puts("Waiting for SIGINT or SIGQUIT...");    signal(SIGINT, foo);    signal(SIGQUIT, foo);    pause();        //等待信号到达    return0;}
复制代码

sigaction

#include <signal.h>

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

signum:信号的值,可以为除 SIGKILL 及 SIGSTOP 外的任何一个特定有效的信号

act:指向结构 sigaction 的一个实例的指针,指定对特定信号的处理

oldact:保存原来对相应信号的处理

struct sigaction {
  void (*sa_handler)(int);
  void (*sa_sigaction)(int, siginfo_t *, void *);
  sigset_t sa_mask;
  int sa_flags;
  void (*sa_restorer)(void);
};

通过sa_mask设置信号掩码集。

信号处理函数可以采用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *, void *)。到底采用哪个要看sa_flags中是否设置了SA_SIGINFO位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t *, void *),此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int),此时只能向处理函数发送信号的数值。

sa_falgs还可以设置其他标志:

SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL

SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用

SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号

复制代码
#include<stdio.h>#include<signal.h>#include<stdlib.h>#include<string.h>#define INPUTLEN 100void inthandler(int);int main(){    struct sigaction newhandler;    sigset_t blocked;       //被阻塞的信号集    char x[INPUTLEN];    newhandler.sa_flags=SA_RESETHAND;    newhandler.sa_handler=inthandler;    sigemptyset(&blocked);      //清空信号处理掩码    sigaddset(&blocked,SIGQUIT);    newhandler.sa_mask=blocked;    if(sigaction(SIGINT,&newhandler,NULL)==-1)        perror("sigaction");    else        while(1){            fgets(x,INPUTLEN,stdin);        //fgets()会在数据的最后附加"\0"            printf("input:%s",x);        }}void inthandler(int signum){    printf("Called with signal %d\n",signum);    sleep(signum);    printf("done handling signal %d\n",signum);}
复制代码

Ctrl-C向进程发送SIGINT信号,Ctrl-\向进程发送SIGQUIT信号。

$ ./sigactdemo
^CCalled with signal 2
^\done handling signal 2
Quit (core dumped)

由于把SIGQUIT加入了信号掩码集,所以处理信号SIGINT时把SIGQUIT屏蔽了。当处理完SIGINT后,内核才向进程发送SIGQUIT信号。

$ ./sigactdemo
^CCalled with signal 2
^Cdone handling signal 2

 由于设置了SA_RESETHAND,第一次执行SIGINT的处理函数时相当于执行了signal(SIGINT,SIG_DFL),所以进程第二次收到SIGINT信号后就执行默认操作,即挂起进程。

修改代码,同时设置SA_RESETHAND和SA_NODEFER。

newhandler.sa_flags=SA_RESETHAND|SA_NODEFER;

$ ./sigactdemo
^CCalled with signal 2
^C

在没有设置SA_NODEFER时,在处理SIGINT信号时,自动屏幕SIGINT信号。现在设置了SA_NODEFER,则当SIGINT第二次到来时立即响应,即挂起了进程。 

原创粉丝点击