注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

多多的爹

 
 
 

日志

 
 

读程序,学习Linux编程(二十)  

2010-08-29 21:32:29|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

3.13. 信号(中断)

接下来进入set_signal_handler,看到了函数sigaction,这章谈谈信号。

之所以将标题改成信号(中断),是希望不要与同步机制里面的信号量混淆。

3.13.1. 信号概念

Linux提供了信号机制,用来中断程序。信号机制其实挺恶心人的一种东西,他能将你的程序突然中断下来,进入到中断处理中。如果你为中断已经写了一个处理函数或者提前告诉系统要忽略这个中断,那么你的工作还好不会受到太大的影响。如果遇到一个你未提前处理的中断,则很可能导致程序崩溃甚至退出。

信号有很多种,每个信号都用一个数字标识。用man kill,可以看到所有的信号定义。/usr/include/signal.h是则是这些信号的定义。

信号来源于系统内核,产生的条件有三种:

1. 用户输入。比如ctrl+c导致内核发送中断信号,ctrl+\导致发送退出信号。

2. 程序执行出错时,内核会发出现错误的信号,比如非法段存取、浮点数溢出,或者除0错。

3. 另外就是由某个程序向另一个程序显式的发生指定的信号了,比如在shell中调用命令kill,或者程序里调用函数kill。

命令:kill [ -signal | -s signal ] pid

函数:int kill(pid_t pid, int sig);

信号的作用就是中断你的进程。然而有很多信号,其默认的行为是杀死进程。比如SIGINT和SIGQUIT。因此要防止这些情况发生,进程需要为信号做相应的处理。当程序为中断做了相应处理后,中断到来后,会将程序从当前运行位置直接跳转到处理位置,处理完成后再回到原位置继续运行。

clip_image001

对待中断有三种方式,一种是啥都不干,一种是忽略他,一种是设定一个处理函数。前两种方式好像是一样的,但其实不同。啥都不干的意思,是指进程按内核定行为方式运行,比如接收到SIGQUIT信号,程序就直接退出。忽略他则是指信号到来后完全忽略他,只当这个行为没有发生过。这种方式也比较野蛮,最好的方式是最三种。

3.13.2. 信号处理

先来了解处理信号的函数。

#include

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);

函数signal设置对信号的处理方式。signum表示信号。handler可以是以下三种情况:

1. SIG_IGN,信号被忽略。

2. SIG_DFL,让内核来处理。

3. 一个函数指针,函数的定义如sighandler_t。据我了解,这个函数定义可以没有参数,也可以没有返回值。

下面是一个例子:

int quit_time = 0;

void handler()

{

printf("%d signal is raised.\n", ++quit_time);

}

void main()

{

signal(SIGQUIT, handler);

while (quit_time <10 u>

{

pause();

}

printf("bye");

}

启动程序后,按ctrl+\向进程发送退出信号,发送一次提示一次,直到10次后,程序退出。

clip_image003

3.13.3. 定时器信号

Linux为定时器定义了信号SIGALRM,当设定的时间来临后,会激发这个信号。有两个方案可以定时:

1. alarm

unsigned int alarm(unsigned int seconds);

设置seconds秒后激发一次信号SIGALRM

2. setitimer

int getitimer(int which, struct itimerval *curr_value);

int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

which指定具体时间类型,new_value可以将时间精确到微秒。只要不取消,每隔new_value的时间,信号SIGALRM会被激发。

3.13.4. 改进的信号处理

signal是早期的Linux信号处理函数,这个函数有天生的问题:

1. 多个信号同时到达

2. 不知道信号到达的原因

3. 不能安全的阻塞其它消息

所以Linux开发人员,又搞了一个新的sigaction函数:

#include

struct sigaction {

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

};

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

还是看例子吧:

void inthandler(int s)

{

printf("Called with signal %d\n", s);

sleep(s);

printf("done handling signal %d\n", s);

}

main()

{

sigset_t blocked;

sigemptyset(&blocked);

sigaddset(&blocked, SIGQUIT);

struct sigaction handler;

handler.sa_handler = inthandler;

handler.sa_flags = SA_SIGINFO;//SA_RESETHAND | SA_RESTART;

handler.sa_mask = blocked;

if (sigaction(SIGINT, &handler, NULL) == -1)

{

perror("failed to set a sigaction");

return;

}

while (1)

{

pause();

}

}

程序运行后,用ctrl+c中断进程,进程进入到inthandler,并开始sleep。此时马上输入ctrl+\,进程并没有马上结束。进程sleep完了,继续中断程序,然后才结束。

3.13.5. 处理不了的信号

并不是所有的信号都能捕获,sigaction就对SIGKILL和SIGSTOP没办法。因此写程序时一定要多参考man。


  评论这张
 
阅读(16)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017