当前位置:网站首页>使用alarm函数实现sleep,使用alarm函数实现对阻塞操作设置超时
使用alarm函数实现sleep,使用alarm函数实现对阻塞操作设置超时
2022-08-03 13:58:00 【站在巨人的肩膀上,温故而知新】
1 相关函数介绍
1.1 函数kill和raise
kill将信号发送给进程。raise函数则允许进程向自身发送信号。
#include <signal.h>
// 成功,返回0;失败,返回-1
int kill(pid_t pid, int signo);
int raise(int signo);
调用raise(signo)等价于调用kill(getpid(), signo)
kill函数的pid参数分为以下4种情况:
(1)pid>0
将信号发送给进程ID为pid的进程
(2)pid=0
将信号发送给与发送进程属于同一进程组的所有进程(发送进程具有权限向这些进程发送信号)
(3)pid<0
将信号给其进程组ID等于pid绝对值,且发送进程具有权限向其发送信号的所有进程
(4)pid==-1
将信号发送给发送进程有权限向它们发送信号的所有进程
进程将信号发送给其他进程需要权限。超级用户可以将信号发送给任一进程。对于非超级用户,规则是发送者的实际用户ID或有效用户ID必须等于接收者的实际用户ID或有效用户ID。
1.2 函数alarm和pause
alarm函数可以设置一个定时器,在将来的某个时刻该定时器会超时。当定时器超时时,产生SIGALARM信号。如果忽略或不捕捉该信号,则默认动作是终止调用alarm函数的进程。
#include <unistd.h>
//返回值:0或之前设置的闹钟时间的余留值
unsigned int alarm(unsigned int seconds);
每个进程只能有一个闹钟时间。如果在调用alarm时,之前已为该进程注册的闹钟时间还没有超时,则该闹钟时间的余留值作为本次alarm函数调用的返回值。以前注册的闹钟时间则被新值代替。如果有之前注册的尚未超过的闹钟时间,且本次调用的seconds值为0,那么其余留值仍作为alarm函数返回,然后取消以前的闹钟时间。
pause函数使调用进程挂起直到捕捉到一个信号。
#include <unistd.h>
//返回值:-1,errno设置为EINTR
int pause(void);
只有执行了一个信号处理程序并从其返回时,pause才返回。这时,pause返回-1,errno设置为EINTR。
2 使用alarm函数实现sleep
使用alarm和pause,进程可以使自己休眠一段指定的时间。
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static void sig_alrm(int signo)
{
/* nothing to do, just return to wake up the pause */
printf("sig_alrm !!! \n");
}
unsigned int sleep1(unsigned int seconds)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(seconds);
printf("alarm start !!!\n");
alarm(seconds); /* start the timer */
pause(); /* next caught signal wakes us up */
printf("alarm done !!!\n");
return(alarm(0)); /* turn off timer, return unslept time */
}
int main(void) {
unsigned int unslept;
unslept = sleep1(5);
printf("unslept:%d \n", unslept);
return 0;
}
测试结果如下:
xxx$ ./sleep1
alarm start !!!
sig_alrm !!!
alarm done !!!
unslept:0
实际上,sleep1函数有竞争关系:alarm在调用pause之前超时。如果发生这种情况,则在调用pause后将不会再捕捉到信号,调用者将永远被挂起。
可以使用setjmp和longjmp来避免如上的竞争条件:
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
static jmp_buf env_alrm;
static void sig_alrm(int signo)
{
printf("sig_alrm!!! \n");
longjmp(env_alrm, 1);
}
unsigned int sleep2(unsigned int seconds)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(seconds);
if (setjmp(env_alrm) == 0) {
printf("alarm start!!! \n");
alarm(seconds); /* start the timer */
pause(); /* next caught signal wakes us up */
printf("after pause 1 !!! \n");
}
// longjmp to here!
printf("after pause 2 !!! alarm done!!! \n");
return(alarm(0)); /* turn off timer, return unslept time */
}
int main(void) {
unsigned int unslept;
unslept = sleep2(5);
printf("unslept:%d \n", unslept);
return 0;
}
测试结果如下:
xxx$ ./sleep2
alarm start!!!
sig_alrm!!!
after pause 2 !!! alarm done!!!
unslept:0
sleep2函数也有问题,涉及到与其他信号的交互。例如如下伪代码:
unsigned int sleep2(unsigned int);
static void sig_int(int);
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)
{
//耗时操作>5s
}
如上程序若SIGINT的信号处理程序先触发,且是耗时操作>5s。则等sleep2(5) 5s超时后,sig_int程序会被突然打断,引起异常。
3 使用alarm函数实现对阻塞操作设置超时
alarm函数还常用于对可能阻塞的操作设置时间上限值。
如下程序,从标准输入读一行,然后将其写到标准输出上。
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXLINE 4096
static void sig_alrm(int);
static jmp_buf env_alrm;
int main(void)
{
int n;
char line[MAXLINE];
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
printf("signal(SIGALRM) error");
if (setjmp(env_alrm) != 0) {
// longjmp here!!!
printf("read timeout \n");
goto out1;
}
alarm(10);
if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0)
printf("read error \n");
alarm(0);
write(STDOUT_FILENO, line, n);
exit(0);
out1:
printf("out1 exit(1) >>> \n");
exit(1);
}
static void sig_alrm(int signo)
{
longjmp(env_alrm, 1);
}
测试结果如下:
xxx$ ./read2
read timeout
out1 exit(1) >>>
xxx$ ./read2
safasdf
safasdf
边栏推荐
猜你喜欢
随机推荐
大型连锁百货运维审计用什么软件好?有哪些功能?
回流和重绘
Nanoprobes金脂质偶联物的相关应用
D the author: d new features
[web penetration] detailed explanation of CSRF vulnerability
1, introduction to petri net
有哪些好用的IT资产管理平台?
TensorFlow离线安装包
十大免费代理ip软件_国内静态ip代理软件
细胞图像数据的主动学习
Zhang Le: The Golden Triangle of R&D Efficiency and Practice in the Field of Demand and Agile Collaboration|Live Review
c语言结构体知识总结
STL——vector
英文邮件总结
金立前高管团队再战手机市场,创立新品牌“FreeYond”
投资75亿卢比!印度宣布建首座存储芯片组装和封测工厂,将于12月量产
The embassy in Iceland reminds Chinese citizens in Iceland to strengthen safety protection
工作流自动化,低代码是解决关键
张乐:研发效能的黄金三角及需求与敏捷协作领域的实践|直播回顾
VMware 虚拟机如何连接网络「建议收藏」