linux c 信号处理

68 篇文章 0 订阅

a.信号处理函数应该是可重入的,容易引发一竞态条件,所以不要在信号处理函数中调用一些不安全的函数。

b.当程序在执行处于阻塞状态的系统调用时接收到信号,并且没有设置忽略该信号时,默认系统调用将被中断,并且设置errno为ENTR。我们可以

用sigaction函数设置信号为SA_RESTART标志来重启被中断的系统调用

fork后子进程的信号位图被清除,原进程设置的信号处理函数不再对新进程起作用


一.产生信号

Sys/types.h signal.h

a)    int kill(pid_t pid ,int sig)

给相应的进程或者进程组发送信号

b)     int raise(int sig) 给当前进程自己发信号;成功返回0,失败返回非0

c) unisd.h

            unsigned int alarm(unsigned int seconds)

在seconds秒后发送sigalarm信号给自己,默认进程收到sigalarm后终止。若不只有一个alarm调用,那最后一个Alarm之前的时间警告都会被取消

 

二.捕获处理信号

Sigkill sigstop不能被捕获或者忽略

1)注册处理方法

Sighandler_t signal(int signum , sighandler_t handler)    handler可以使处理方法的指针,也可以是SIG_IGN/SIG_DEF

出错返回SIG_ERR,并erron

2)读取或者修改指定信号的处理动作

Int sigaction(int signum,const struct sigaction *newaction,struct sigaction *oldact)

Struct sigaction

{       

         Void(*sa_handler)(int); //信号处理函数或者SIG_IGN /SIG_DEF        

         Void(*sa_sigaction)(int ,siginof_t *,void *);

sigset_t sa_mask;//处理函数 执行时要屏蔽的信号

int sa_flags;//信号收到时,程序的如何处理

void (*sa_restorer)(void);

};

sa_flags值:
SA_NOCLDSTOP //此标志为on时,假如signum的值是SIGCHLD,则在子进程停止或恢复执行时不产生SIGCHLD信号,不会传信号给调用本系统调用的进程。
SA_NOCLDWAIT //此标志为on时,当调用此系统调用的进程之子进程终止时--signum的值是SIGCHLD,系统不会建立zombie进程。

SA_SIGINFO  //使用sa_sigaction作为信号处理函数,而不是默认的sa_handler,它给进程提供了更多相关信息
SA_RESETHAND //此标志为on时,信号处理函数接收到信号后,会先将对信号处理的方式设为预设方式-恢复默认,而且当函数处理该信号时,后来发生的信号将不会被阻塞。
SA_ONSTACK //如果利用sigaltstack()建立信号专用堆栈,则此标志会把所有信号送往该堆栈,调用该堆栈上的信号处理函数。
SA_RESTART //此标志为on时,核心会自动重启信号中断的系统调用,否则返回EINTR错误值。
SA_NODEFER //当此标志为on时,在信号处理函数处置信号的时段中,核心程序不会把这个间隙中产生的信号阻塞。默认情况下我们期望在处理一个信号时不再接受同种信号,否则会引起一些竟态条件。
SA_SIGINFO //此标志为on时,指定信号处理函数需要三个参数,所以应使用sa_sigaction替sa_handler。


Sigaddset(&newaction.sa_mask,SIGALARM) // 把sigalarm添加到处理方法的屏蔽信号中

Sigemptyset(sigset_t &set);

Sigismember(sigset_t &set,int sig)

int sigdelset(sigset* _set,int signo)

int sigfillset(sigset_t * set);用来将参数set信号集初始化,然后把所有的信号加入到此信号集里即将所有的信号标志位置为1,屏蔽所有的信号


sigaction封装成signal

int mysignal(int signo, Void(*func)(int))

{

     Struct sigaction newaction,oldaction;

     newaction.sa_handler=func;

     Sigemptyset(&newaction.sa_mask);//执行func时,不屏蔽任何信号

     newaction.sa_flags=0;

     return sigaction(signo,&newaction,&oldaction);

}

三.信号阻塞

a) 获取、修改进程的信号屏蔽---只是阻塞在那里,解开阻塞后这些信号还是会提交给进程

Int sigprocmask(int how,const sigset_t *newest,sigset_t*oldset);

How: SIG_BLOCK / SIG_UNBLOCK / SIG_SETMASK(将进程的信号掩码设置成newset)

Sigprocmask只能用在单线程中,多线程用pthread_sigmask

b)进程挂起等待一个信号的到来,执行相应的后处理,sigsuspend执行过程中mask中的信号是屏蔽掉了的

Int sigsuspend(const sigset_t *mask)

c)获取阻塞的信号-若是我们取消对被挂起信号的屏蔽,它会立即被进程接受

Int sigpending(sigset_t *set)

注意:1.信号处理函数访问了全局变量,那在定义这全局变量时要声明为volatile,以避免编译器不恰当的优化

           2.在信号处理函数中只能调用可重入的库函数,不能调用free()、malloc()、标准i/o库函数


四。与网络编程有关的的信号

1.SIGHUP:当挂起 进程的控制终端时,触发。对于没有控制终端的网络后台程序常利用SIGHUP信号来强制服务器重新读取配置文件

2.SIGPIPE:默认情况下,往一个读端关闭的管道或socket连接中写数据将触发,程序默认收到SIGPIP结束进程,我们往往不希望因为错误的写操作而导致进程退出。

引起SIGPIPE信号的写操作将设置errno为EPIPE.

我们可以使用send函数的MSG_NOSIGANL标志来禁止写操作触发sigpipe信号,在这种情况下,我们应该使用send函数反馈的errno来判读管道或者socket连接的读端是否关闭

此外我们可以利用I/O 复用系统调用来监测管道和socket的读端是否关闭,以poll为例(参数revents可以包含任意events中指定的事件,或是POLLERR、POLLHUP、POLLNVAL三者之一),当管道读端关闭时,写端文件描述符上的pollhup事件将触发;当socket连接被对方关闭时,socket上的POLLRDHUP事件(since Linux 2.6.17)将被触发

3.SIGURG:内核通知带外数据到达有两种方法:

a。i/o复用中select等系统调用在接收到带外数据时,会在异常事件里面报告,接收是recv设置MSG_OOB标志就可以了

b。使用SIGURG信号

signal(SIGURG, sigurg_handler);//在sigurg_handler函数中recv用带MSG_OOB标志接收带外数据

// 必须用F_SETOWN设置接收SIGIO和SIGURG信号的进程ID或进程组ID
fcntl(fd, F_SETOWN, getpid());

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值