信号处理函数

信号处理函数


sigaction的用法

int sigaction (

        int signo,

        const struct sigaction *act,

        struct sigaction *oldact

);

这个函数主要是用于改变或检测信号的行为。

第一个参数是变更signo指定的信号,它可以指向任何值,SIGKILL,SIGSTOP除外

第二个参数,第三个参数是对信号进行细粒度的控制。

如果*act不为空,*oldact不为空,那么oldact将会存储信号以前的行为。

如果act为空,*oldact不为空,那么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_handler是一个函数指针,主要是表示接收到信号时所要采取的行动。此字段的值可以是SIG_DFL,SIG_IGN.分别代表默认操作与内核将忽略进程的信号。这个函数只传递一个参数那就是信号代码。

当SA_SIGINFO被设定在sa_flags中,那么则会使用sa_sigaction来指示信号处理函数,而非sa_handler.

sa_mask设置了掩码集,在程序执行期间会阻挡掩码集中的信号。

sa_flags设置了一些标志, SA_RESETHAND当该函数处理完成之后,设定为为系统默认的处理模式。SA_NODEFER 在处理函数中,如果再次到达此信号时,将不会阻塞。默认情况下,同一信号两次到达时,如果此时处于信号处理程序中,那么此信号将会阻塞。

SA_SIGINFO表示用sa_sigaction指示的函数。

sa_restorer已经被废弃。

sa_sigaction所指向的函数原型:

void my_handler(int signo, siginfo_t *si, void *ucontext);

第一个参数: 信号编号

第二个参数:指向一个siginfo_t结构。

第三个参数是一个ucontext_t结构。

其中siginfo_t结构体中包含了大量的信号携带信息,可以看出,这个函数比sa_handler要强大,因为前者只能传递一个信号代码,而后者可以传递siginfo_t信息。

typedef struct siginfo_t {

        int si_signo;//信号编号

        int si_errno;//如果为非零值则错误代码与之关联

        int si_code;//说明进程如何接收信号以及从何处收到

        pid_t si_pid;//适用于SIGCHLD,代表被终止进程的PID

        pid_t si_uid;//适用于SIGCHLD,代表被终止进程所拥有进程的UID

        int si_status;//适用于SIGCHLD,代表被终止进程的状态

        clock_t si_utime;//适用于SIGCHLD,代表被终止进程所消耗的用户时间

        clock_t si_stime;//适用于SIGCHLD,代表被终止进程所消耗系统的时间

        sigval_t si_value;

        int si_int;

        void * si_ptr;

        void* si_addr;

        int si_band;

        int si_fd;

};

sigqueue的用法

sigqueue( pid_t pid, int signo, const union sigval value)

union sigval  {int sival_int, void*sival_ptr };

sigqueue函数类似于kill,也是一个进程向另外一个进程发送信号的。

但它比kill函数强大。

第一个参数指定目标进程的pid.

第二个参数是一个信号代码。

第三个参数是一个共用体,每次只能使用一个,用来进程发送信号传递的数据。

或者传递整形数据,或者是传递指针。

发送的数据被sa_sigaction所指示的函数的siginfo_t结构体中的si_ptr或者是si_int所接收。

sigpending的用法

sigpending(sigset_t set);

这个函数的作用是返回未决的信号到信号集set中。

即未决信号集,未决信号集不仅包括被阻塞的信号,也可能包括已经到达但没有被处理的信号。

示例1: sigaction函数的用法

void signal_set1(int x) { //信号处理函数,只传递一个参数信号代码

        printf("xxxxx/n");

        while(1)  {

                //

         }

}

void signal_set(struct sigaction *act)

{

        switch(act->sa_flags) {

        case (int)SIG_DFL:

                printf("using default hander/n");

                break;

        case (int)SIG_IGN:

                printf("ignore the signal/n");

                break;

        default:

                printf("%0x/n",act->sa_handler);

        }

}

int main(int argc, char** argv)

{

        int i;

        struct sigaction act,oldact;

        act.sa_handler = signal_set1;

        act.sa_flags = SA_RESETHAND;

        //SA_RESETHANDD 在处理完信号之后,将信号恢复成默认处理

        //SA_NODEFER在信号处理程序执行期间仍然可以接收信号

        sigaction (SIGINT,&act,&oldact) ;//改变信号的处理模式

        for (i=1; i<12; i++)

        {

                printf("signal %d handler is : ",i);

                sigaction (i,NULL,&oldact) ;

                signal_set(&oldact);//如果act为NULL,oldact会存储信号当前的行为

                //act不为空,oldact不为空,则oldact会存储信号以前的处理模式

        }

        while(1) {

                //等待信号的到来

        }

        return 0;

}

运行结果:

[root@localhost C]# ./s2

signal 1 handler is : using default hander

signal 2 handler is : 8048437

signal 3 handler is : using default hander

signal 4 handler is : using default hander

signal 5 handler is : using default hander

signal 6 handler is : using default hander

signal 7 handler is : using default hander

signal 8 handler is : using default hander

signal 9 handler is : using default hander

signal 10 handler is : using default hander

signal 11 handler is : using default hander

xxxxx

解释:

sigaction(i,NULL,&oldact);

signal_set(&oldact);

由于act为NULL,那么oldact保存的是当前信号的行为,当前的第二个信号的行为是执行自定义的处理程序。

当按下CTRL+C时会执行信号处理程序,输出xxxxxx,再按一下CTRL+C会停止,是由于SA_RESETHAND恢复成默认的处理模式,即终止程序。

如果没有设置SA_NODEFER,那么在处理函数执行过程中按一下CTRL+C将会被阻塞,那么程序会停在那里。


示例2: sigqueue向本进程发送数据的信号

void myhandler(int signo, siginfo_t *si, void *ucontext);

int main()  {

        union sigval val;//定义一个携带数据的共用体

        struct sigaction oldact,act;

        act.sa_sigaction = myhandler;

        act.sa_flags = SA_SIGINFO;//表示使用sa_sigaction指示的函数,处理完恢复默认,不阻塞处理过程中到达下在被处理的信号

        //注册信号处理函数

        sigaction(SIGUSR1, &act, &oldact);

        char data[100];

        int num=0;

        while( num < 10 )  {

                sleep( 2 );

                printf("等待SIGUSR1信号的到来/n");

                sprintf(data, "%d", num++);

                val.sival_ptr=data;

                sigqueue( getpid(), SIGUSR1, val );//向本进程发送一个信号

            }

}

void myhandler ( int signo, siginfo_t *si, void *ucontext )  {

        printf("已经收到SIGUSR1信号/n");

        printf("%s/n",(char*)(si->si_ptr));

}

程序执行的结果是:

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

0

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

1

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

2

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

3

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

4

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

5

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

6

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

7

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

8

等待SIGUSR1信号的到来

已经收到SIGUSR1信号

9

解释: 

本程序用sigqueue不停的向自身发送信号,并且携带数据,数据被放到处理函数的第二个参数siginfo_t结构体中的si_ptr指针,当num<10时不再发。

一般而言,sigqueue与sigaction配合使用,而kill与signal配合使用。


示例3: 一个进程向另外一个进程发送信号,并携带信息

发送端:

int main()  {

        union sigval value;

        value.sival_int=10;

        if ( sigqueue(4403, SIGUSR1, value) == -1 )  {  //4403是目标进程pid

                perror("信号发送失败/n");

        }

        sleep(2);

}

接收端:

void myhandler ( int signo, siginfo_t*si, void *ucontext );

int main () {

        struct sigaction oldact, act;

        act.sa_sigaction = myhandler;

        act.sa_flags = SA_SIGINFO | SA_NODEFER;

        //表示执行后恢复,用sa_sigaction指示的处理函数,在执行期间仍然可以接收信号

        sigaction ( SIGUSR1, &act, &oldact );

        while ( 1 )  {

                sleep ( 2 );

                printf("等待信号的到来/n");

        }

}

void myhandler ( int signo, siginfo_t *si, void *ucontext ) {

        printf("the value is %d/n",si->si_int);

}


示例4: sigpending的用法

sigpending (sigset_t *set )将未决信号放到指定的set信号集中去,未决信号包括被阻塞的信号和信号到达时但还没来得及处理的信号

void myhandler ( int signo, siginfo_t *si, void *ucontext );

int main()  {

        struct sigaction oldact, act;

        sigset_t oldmask, newmask, pendingmask;

        act.sa_sigaction = myhandler;

        act.sa_flags = SA_SIGINFO;

        sigemptyset( &act.sa_mask );  //首先将阻塞集合设置为空,即不阻塞任何信号

        //注册信号处理函数

        sigaction(SIGRTMIN + 10, &act ,&oldact);

        //开始阻塞

        sigemptyset( &newmask );

        sigaddset( &newmask, SIGRTMIN + 10);

        printf("SIGRTMIN + 10 blocked/n");

        sigprocmask( SIG_BLOCK , &newmask ,&oldmask );

        sleep(20);  //为了发出信号

        printf("now begin to get pending mask/n");

        if ( sigpending( &pendingmask ) < 0 )  {

                perror("pendingmask error");

        }

        if ( sigismember( &pendingmask, SIGRTMIN + 10 ) )  {

                printf("SIGRTMIN+10 is in the pending mask/n");

        }

        sigprocmask( SIG_UNBLOCK, &newmask, &oldmask);

        printf("SIGRTMIN+10 unblocked/n");

}

//信号处理函数

void myhandler ( int signo, siginfo_t *si, void *ucontext )  {

        printf("receive signal %d/n",si->si_signo);

}

程序执行:

在另一个shell发送信号:

kill -44 4579

SIGRTMIN +10 blocked

now begin to get pending mask

SIGRTMIN +10 is in the pending mask

receive signal 44

SIGRTMIN +10 unblocked

可以看到SIGRTMIN由于被阻塞所以处于未决信号集中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容

  • 信号的基本概念 信号被认为是一种软件中断(区别于硬件中断),信号机制提供了一种在单进程/线程下处理异步事件的方法。...
    小叶大孟阅读 1,890评论 0 1
  • 信号(signal)是一种软件中断,它提供了一种处理异步事件的方法,也是进程间惟一的异步通信方式。在Linux系统...
    夏大王2019阅读 996评论 0 1
  • 对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号,为 Linux 提供了一种处理异步事件...
    故事狗阅读 84,641评论 2 62
  • 生理节奏 所有的生命都受到日--夜这种自然节律的影响。你的身体受一种被称作生理节律的时间周期所调节:你的唤醒水平、...
    牧明不是木牧阅读 352评论 0 1
  • 1、感赏我的生命中出现的每一个人,其实每一个人都有不易的地方,可是每一个人都在努力的活着,并努力的活好,自己也是每...
    后来来了阅读 185评论 0 2