信号处理函数sigaction()

来源:互联网 发布:cc网络验证模块源码 编辑:程序博客网 时间:2024/04/16 23:54

sigaction():信号处理函数 可以携带信息~

头文件 #include <signal.h>

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

一个参数为信号的值,可以为除SIGKILLSIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。

第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理可以为空,进程会以缺省方式对信号处理

第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldactNULL

如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。

struct sigaction{    union    {        __sighandler_t _sa_handler;        void (*_sa_sigaction)(int, struct siginfo *, void *);    } _u    sigset_t sa_mask;    unsigned long sa_flags;    void (*sa_restorer)(void);} 

1联合数据结构中union的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数

_sa_handler指定的处理函数只有一个参数,即信号值,所以信号不能传递除信号值之外的任何信息;

_sa_sigaction是指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参数为信号值,第三个参数没有使用(posix没有规范使用该参数的标准),第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值

typedef struct{    int si_signo;  /*信号值,对所有信号有意义*/    int si_errno;  /*errno值,对所有信号有意义*/    int si_code;   /*信号产生的原因,对所有信号有意义*/    union    {        sigval si_value;    } }siginfo_t;//结构的第四个域同样为一个联合数据结构:union sigval{    int si_int;    void *si_ptr;}

深深的不能理解为什么结构体中的第四个变量又多次一举声明为sigval?

像下面这样不是更好?是不是因为处理的信号不同,结构体里的值也会发生变化?

// 自己理解typedef struct{    int si_signo;  /*信号值,对所有信号有意义*/    int si_errno;  /*errno值,对所有信号有意义*/    int si_code;   /*信号产生的原因,对所有信号有意义*/    union    {        int si_int;        void *si_ptr;    } }siginfo_t;// 

采用联合数据结构,说明siginfo_t结构中的si_value要么持有一个4字节的整数值,要么持有一个指针,这就构成了与信号相关的数据。

接受信号例子:

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <sys/types.h>#include <unistd.h>void new_op(int,siginfo_t*, void*);int main(int argc,char **argv){struct sigaction act;// 创建sigaction结构体int sig;pid_t pid;                      pid=getpid();        printf("PID is %d\n", (int)pid);sig=atoi(argv[1]);  //输入时第一个参数 信号的值        (kill -l) 可以查看所有信号            sigemptyset(&act.sa_mask);act.sa_sigaction=new_op;//处理函数act.sa_flags=SA_SIGINFO;//标志if(sigaction(sig,&act,NULL)<0){printf("install sigal error\n");exit(0);}while(1){sleep(2);printf("wait for the signal\n");}}void new_op(int signum,siginfo_t *info,void *myact){printf("the int value is %d \n",info->si_int);}

sa_sigaction函数指针指向了处理函数new_op,在接收到规定信号,执行相应的new_op 操作,并将获得的值(info->si_int)显示出来

也就是说在编程中,对于sigaction()特定信号的处理,只需要将指针指向sa_sigaction 指向处理函数就行,剩下数据的接受可在处理函数参数  siginfo_t 中直接操作

此时的new_op 更像一个中断函数

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@ubuntu:~/Desktop$ ./sig1 50 //输入参数


PID is 3344      // 结果显示
wait for the signal
wait for the signal
wait for the signal
wait for the signal
the int value is 8
wait for the signal
wait for the signal
wait for the signal

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

发送信号例子:

系统调用sigqueue发送信号时,sigqueue的第三个参数就是sigval联合数据结构,当调用sigqueue时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <sys/time.h>#include <unistd.h>#include <sys/types.h>// sigqueue 发送信号信息,带sival_int的信息main(int argc,char **argv){pid_t pid;int signum;union sigval mysigval;signum=atoi(argv[1]);    //要发送信号的信号值pid=(pid_t)atoi(argv[2]);//发送进程的pidmysigval.sival_int=8;//不代表具体含义,只用于说明问题if(sigqueue(pid, signum, mysigval)==-1){printf("send error\n");exit(0);}sleep(2);}
@ubuntu:~/Desktop$ ./sig2 50 3344 //输入参数


程序运行次序 先运行sig1 使其不断的等待接收 再运行sig2 并在后面加入信号值为50 进程号(pid)为3344参数

结果解释:当sig1 不断等待时,如果sig2发送的信号到达,就显示the int value is 8 表示已经接收到信号


二。 signal()


#include <signal.h>
void (*signal( int signum, void(*handler) (int)))(int);

第一个参数指定信号的值,第二个参数指定针对前面信号值的处理

如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR

Linux中signal 和signalaction 的区别就在是否能携带信号信息,在Uinx中貌似还有区别


三.实时信号 非实时信号


// 这个例子主要是对于实时信号和非实时信号阻塞的验证// 利用另一个终端连续发送 kill -SIGRTMIN 进程号 可验证实时信号是可靠的,不会丢失// 利用在本终端连续发送ctrl+c可发现最终是受到一个信号! 即信号不可靠//方法:先将两个信号屏蔽,并sleep一会儿 ,这期间连续发送信号~#include <stdio.h>#include <string.h>#include <signal.h>#include <unistd.h>void sig_handler(int,siginfo_t*,void*);int main(int argc,char**argv){    struct sigaction act;    sigset_t newmask, oldmask;    int rc;     sigemptyset(&newmask);      sigaddset(&newmask, SIGINT); //非实时信号     sigaddset(&newmask, SIGRTMIN); //实时信号    sigprocmask(SIG_BLOCK, &newmask, &oldmask); //屏蔽信号,使其不会立即执行信号的动作    act.sa_sigaction = sig_handler;    act.sa_flags = SA_SIGINFO;     if(sigaction(SIGINT, &act, NULL) < 0)    {        printf("install sigal error\n");    }     if(sigaction(SIGRTMIN, &act, NULL) < 0)    {        printf("install sigal error\n");    }     printf("pid = %d\n", getpid());     sleep(20); // 休眠中 ,发送过来的信号会排队    sigprocmask(SIG_SETMASK, &oldmask, NULL); //打开屏蔽,信号执行相应的操作    return 0;}void sig_handler(int signum,siginfo_t *info,void *myact){    if(signum == SIGINT)        printf("Got a common signal\n");    else        printf("Got a real time signal\n");} 

非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。


四。信号集合

信号集的数据类型

typedef struct {
         unsigned long sig[_NSIG_WORDS];
} sigset_t

信号集用来描述信号的集合,linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。下面是为信号集操作定义的相关函数:

#include <signal.h>int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);int sigaddset(sigset_t *set, int signum)int sigdelset(sigset_t *set, int signum);int sigismember(const sigset_t *set, int signum);sigemptyset(sigset_t *set)初始化由set指定的信号集,信号集里面的所有信号被清空;sigfillset(sigset_t *set)调用该函数后,set指向的信号集中将包含linux支持的64种信号;sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号;sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号;sigismember(const sigset_t *set, int signum)判定信号signum是否在set指向的信号集中。











0 0
原创粉丝点击