
Ctrl-C终止程序运行,此时运行的程序就会收到对应的信号,然后终止程序运行。
运行程序,然后按Ctr-c键会得到如下结果:
一般情况下,按下Ctrl-C后程序直接退出,这个简单的例子里我们捕获了终止信号,进行
了自己的处理:打印出一段信息,然后main函数运行完毕。事实上,我们完全可以进行自由
地进行其他处理,比如不退出运行,虽然这不符合该信号的常规定义。
下面我们从这个简单的例子出发,详细分析
根据是否会被信号中断,系统调用分为两类:“慢”系统调用和其他。“慢”系统是一类可能
永远阻塞调用者的系统调用。
如果线程捕获了一个信号,但线程被阻塞在一个“慢”系统调用(例如从网络中读取一些数据)
,此时系统调用会被中断,返回错误且 errno 被设置为 EINTR 。
这样设计的原因是我们认为当一个信号被捕获到时,说明发生了重要的事件,应当唤醒线程
来处理事件。
这样的设计也带来了一些问题,因为某些读取稿搭调用属于可中断的系统调用,每次返回时,
程序都要判断是否是因为捕获信号导致的失败,如果是谨困,需要进行重试。这样一来编码
非常繁琐,因此有些系统对一些“慢”系统调用支持自动重试。
信号处理函数的安全性问题产生的原因在于,信号可能随时被捕获,信号被捕获时,线程
可能处于任何状态,因此,在信号处理函数中,调用某些函数,可能导致不可预测的危险
行为键晌拿。
比如,当信号被捕获时,线程正在调用 printf ,如果信号处理函数中也调用 printf 函数
可能会导致不可预测的风险。
风险的原因和 printf 函数的实现密切相关。因为 printf 函数包含了一个缓冲区,缓冲区
里包含了很多状态变量,当正在调用 printf 被中断时,缓冲区中的很多变量处于中间状态
如果在信号处理函数中在调用 printf 的话,就会导致不可预测的危险。
确保信号处理函数安全性的做法是在信号处理函数内部,只能调用可重入的函数(reentrant
function)。
第一步:在vi中书写程序father2.c,代码如下:#include<stdio.h>
#include<time.h>
#include<sys/types.h>
void show_systime(void)
main()
{
pid_t pid
int i
pid=fork()
if(pid<0)
{
perror("filed ehwn creating new process\n"知运)
exit(1)
}
else
if(pid==0)
{show_systime()<br/><br/>}
else
{wait(NULL)<br/><br/>喊猛耐for(i=1i<=100i++)<br/><br/>{printf("%d",i)<br/><br/>郑春printf("\n")}
}
}
void show_systime(void)
{
time_t t
if(time(&t)==((time_t)-1))
{printf("Error when getting time!\n")<br/><br/>exit(1)}
else{
char *tt
tt=ctime(&t)
printf("now is %s\n",tt)}
}
由于system函数的实现基本原理是使用fork函数创建一个子进程,用子进程调用exec函数,之后将子进程运行的内容替换成了目标程序。如果不阻塞SIGCHLD信号,那么如果在调用system函数之前还创建了一个其它的子进程,那么当system函数中fork创建的子进程结束后会给父进程发送SIGCHLD信号,如果此时父进程设置的信号处理方式是捕捉而且在信号处理函数中调用了wait函数,那么system函数就无法根据其函数中创建的子进程返回状态获取相应的返回值。记得有这样的规定,system函数的返回应该是函数中创建子进程的返回状态。所以为了能保证system能够正确获取system函数中创建的子进程返回状态,SIGCHLD信号必须被阻塞。同样,为了保证system函数不出现其它的一些问题,要求system函数要忽略SIGINT和SIGQUIT信号,如果system函数调用的程序是交互式的,如“ed”,就可能出现一些小问题。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)