免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2628 | 回复: 0
打印 上一主题 下一主题

【总结】alarm(...),pause(...)的用处 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-20 10:35 |只看该作者 |倒序浏览
unsigned int alarm(unsigned int seconds);
每个进程只能有一个ALARM,所以对这个函数的用法要考虑进程原来是否已经有一个ALARM。
1. 进程先前没有ALARM,则用alarm(...)可以设置一个ALARM,时间到的时候就会1)如果没有设置捕捉SIGALARM,则终止进程 2).如果设置了捕捉SIGALARM,则运行用户捕捉函数。
2. 进程已经有一个ALARM。调用alarm(...),则用现在设置的ALARM覆盖原来的ALARM,返回值为以前那个ALARM的剩余时间。

int pause(void);
使调用的进程挂起,直到捕捉到一个信号。从该信号处理函数返回后,pause()才返回。
Q1:如果这个信号的处理方式是SIG_IGN呢?
A:pause不会返回,这个信号将会被进程忽略。

alarm(),pause()的用处:
1. 制造sleep函数:
static void
sig_alrm(int signo)
{
return; /* nothing to do, just return to wake up the pause */
}
unsigned int
sleep1(unsigned int nsecs)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
  return(nsecs);
alarm(nsecs);  /* start the timer */
pause();   /* next caught signal wakes us up */
return( alarm(0) ); /* turn off timer, return unslept time */
}
这种实现有些问题,
a. 如果进程原来有一个ALARM,调用了sleep1(sec)后,原来的ALARM就会被破坏。这应该不是我们的本意。
b. 这里的sleep1里面修改了对SIGALRM的配置,将其设置成为了用函数sig_alrm捕捉。
更正方法:我们应该保存原来的设置,在函数返回的时候再恢复成原来的进程对SIG_ALRM的配置。具体为:保存signal()的返回值。
c. 如果由于系统调度的问题,可能导致在 alarm(nsecs)和pause()之间ALARM就超时了,而我们对ALARM的处理函数里面实际上什么也没有做,这样就可能导致进程永远的睡眠了。这是一个竞态条件。
解决方法:1)用setjmp 2)用sigprocmask, sigsuspend方法。
-----用setjmp来解决issue c------
static jmp_buf env_alrm;
static void
sig_alrm(int signo)
{
longjmp(env_alrm, 1);
}
unsigned int
sleep2(unsigned int nsecs)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
  return(nsecs);
if (setjmp(env_alrm) == 0) {
  alarm(nsecs);  /* start the timer */
  pause();   /* next caught signal wakes us up */
}
return( alarm(0) );  /* turn off timer, return unslept time */
}
-----用setjmp来解决issue c ---end---
这里我们解决了竞态条件,即使在在alarm(nsecs)和pause()之间就超时了,这里的sig_alrm()调用 longjmp(env_alrm, 1);可以使sleep2返回。
但是这里的longjmp(...)又会引入另一个问题:
sleep2会终端某个其他的信号处理程序。
int main(void)
{
unsigned int unslept;
if (signal(SIGINT, sig_int) == SIG_ERR)
  err_sys("signal(SIGINT) error");
unslept = sleep2(5);
printf("sleep2 returned: %u\n", unslept);
exit(0);
}
static void sig_int(int signo)
{
int    i;
volatile int j,k;
printf("\nsig_int starting\n");
for (i = 0; i
printf("sig_int finished\n");//可能得不到运行就被sleep2中的ALARM中断了。
return;
}
$a.out
^C
sig_int starting
sleep2 returned: 0   //sleep2(5);执行完毕。
在这里我们可以看出,终端处理函数sig_int没有执行完整。
而如果我们使用sleep1则不会导致sig_int的提前终止。即使sleep1的时间到了,也要等到终端处理程序sig_int运行完了。
从这里可以看出,涉及到信号的处理我们要非常细心。

2. alarm()还经常用来对一个可能阻塞的操作设置一个时间上限值。
详细的信息可以看看page 218 in apue.








本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/59712/showart_2000922.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP