跟着iMX28x开发套件学linux-06

六、linux应用编程之四:信号

linux同时运行着多个进程,进程通信就显得很有必要。实际上平时使用linux系统的时候也经常利用信号对进程进行通信,比如想要shell里终止一个正在运行的程序的时候,按下Ctrl+c的时候,等于向进程发送了一个SIGINT信号。

信号本身并不复杂,就是int类型的常量,用kill -l命令可以查看支持的信号。需要关注的是进程对信号的处理。当进程接收到信号,一般有三种响应方式:一是类似中断服务函数的响应方式;二是进程忽略信号,即不进行响应;三是系统默认的响应方式,一般是终止线程。

对于一般的信号,线程采用系统默认的响应方式即可,但是某些特别的情况下,系统默认的响应方式不能满足需求,那就需要自己编写响应函数,然后把该信号的响应方式设置为中断服务的响应方式,当然这里的中断服务函数要指向事先编写好的响应函数。

设置响应方式的函数为sigaction()函数,下面介绍这个函数。

sigaction()函数

1) 函数原型 int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

2) 输入参数 signum,哪个信号的响应要被设置;

*actsigaction结构体的指针,用来配置设置项;

*oldactsigaction结构体的指针,可以为NULL

3)  int,成功返回0,失败返回-1

这个函数从表面看只是选定了要设置响应的信号,但是关于具体的设置并没有表现出来,比如要把中断服务函数设置成哪个响应函数,在处理选定的信号的时候要不要屏蔽一些信号等等。实际上这些内容都在sigaction结构体中。

sigaction结构体

   

1) *sa_handler : 函数指针,指向有一个int类型参数以及无返回值的函数。

2) *sa_sigaction : 同上,输入参数不同,指向更高级的响应函数,可以为空。

3) sa_mask : 屏蔽设置,设置哪些信号被屏蔽。

4) sa_flags : 响应选项,可以配置响应方式等的参数。

在实际使用的时候,先声明一个sigaction结构体,然后逐个初始化这个结构体的值。sa_handler就是指定信号发生时调用的函数的指针;sa_sigaction指向更高级的响应函数,前提是sa_flags要设置SA_SIGINFOsa_mask可以调用 sigemptyset()sigaddset()sigdelset()分别对这个信号集进行清空、增加和删除被屏蔽信号的操作,将sa_mask的引用作为这三个函数的输入参数即可;sa_flags可以是多个配置选项的或,取值如下:

flags

描述

SA_RESTART

使被信号打断的系统调用自动重新发起。

SA_NOCLDSTOP

使父进程在它的子进程暂停或继续运行时不会收到SIGCHLD 信号。

SA_NOCLDWAIT

使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程。

SA_NODEFER

使对信号的屏蔽无效,即在信号处理函数的执行期间仍能发出这个信号。

SA_RESETHAND

信号被处理后重新设置处理方式到默认值。

SA_SIGINFO

使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数。

 使用Ctrl+c向程序发送SIGINT信号示例

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

//sa_handler function
void ouch(int sig){
    printf("\nOuch! I got a signal %d\n", sig);
}

int main(){
    
    struct sigaction act;
    act.sa_handler = ouch;                //link handler
    sigemptyset(&act.sa_mask);            //empty signal mask
    act.sa_flags = SA_RESETHAND;            //use default after due signal
    sigaction(SIGINT, &act, NULL);        //use params to set signal action
    
    while(1){
        printf("sleep(1)\n");
        sleep(1);
    }
    return 0;
}

 

运行结果:

   

父进程使用kill()向子进程发送信号示例

   

  运行结果:

   

 

posted on 2018-11-05 22:19  diskiii  阅读(504)  评论(0编辑  收藏  举报

导航