当前位置:网站首页>使用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:0sleep2函数也有问题,涉及到与其他信号的交互。例如如下伪代码:
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边栏推荐
猜你喜欢

MSF编码与upx加壳过杀软

冷链行业商业供应链系统:实现全流程数字化协同,激活企业迸发市场活力

Relia Tech活性VEGFR重组蛋白丨小鼠 VEGF120实例展示

Ansible中的角色使用

鸿湖万联扬帆富设备开发板正式合入OpenHarmony主干

Nanoprobes金脂质偶联物的相关应用

PCL 点云按时间进行分段

保健用品行业B2B电子商务系统:供采交易全链路数字化,助推企业管理精细化
![[A summary of the sorting and use of activation functions in deep learning]](/img/c2/abec82f4f1e8ce3c70b6d98b24e7eb.png)
[A summary of the sorting and use of activation functions in deep learning]

苹果终于认清现实,销量成为优先考虑,iPhone14将不涨价
随机推荐
Insert or Merge
使用域名注册服务 Domains配置域名【华为云至简致远】
“芯片法案”通过后,美光承诺在美国扩产
Petri net-2, directed net
苹果终于认清现实,销量成为优先考虑,iPhone14将不涨价
为什么手动启动GBase 8c数据库中GTM节点
OpenHarmony高校技术俱乐部计划发布
第二讲 软件生命周期
动作条的多项复选
MySQL【存储过程与函数】
HCIP Day 16 Notes (SVI, Spanning Tree Protocol)
LARS (Least Angle Regression)
c语言结构体知识总结
MySQL【视图】
Nanoprobes Ni-NTA-Nanogold——用于 His 标签标记和检测
【深度学习中的激活函数的整理与使用总结】
Nanoprobes EnzMet - 酶金相相关介绍及应用
背后的力量 | 提升医疗服务“速度“和“温度” 华云数据助力上海国际医学中心加速智慧医院建设
QImageReader
优思学院|2022年获美质协ASQ和ILSSI奖项的《精益六西格玛的十条戒律》