信号捕获之pause函数和竟态条件(mysleep)
来源:互联网 发布:想购买个4星的淘宝店铺 编辑:程序博客网 时间:2024/06/04 19:37
相关博客
Linux下的信号(一)
http://blog.csdn.NET/double_happiness/article/details/72848372
Linux下的信号(二)
http://blog.csdn.Net/double_happiness/article/details/72897148
pause函数
#include <unistd.h>int pause(void);
返回值:只有出错返回值,没有正确返回值
信号的处理动作与pause的返回状态说明
1)默认:终止进程,pause函数没有机会返回;
2)忽略:进程继续处于挂起状态,pause不返回;
3)自定义动作:调用自定义处理函数后返回-1,errno设置为EINTR;
下面通过模拟实现sleep函数来说明这种切换
1)main函数调用my_sleep函数,后者调用sigaction注册了SIGALRM信号的处理函数handler。
2)调用alarm(times)设定闹钟。
3)调用pause等待,内核切换到别的进程运行。
4)times秒之后,闹钟超时,内核发SIGALRM给这个进程。
5)从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是handler。
6)切换到用户态执行handler函数,进入handler函数时SIGALRM信号被自动屏蔽, 从handler函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程。
7) pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理动作。
普通版的mysleep代码实现:(利用alarm和pause函数实现)
#include<stdio.h>#include<unistd.h>#include<unistd.h>void handler(int sig){ printf("my sig is %d\n",sig);}int mysleep(int time){ struct sigaction new,old; int usleep=0; new.sa_handler=handler; sigemptyset(&new.sa_mask); new.sa_flags=0; sigaction(SIGALRM,&new,&old); alarm(time); pause(); usleep=alarm(0); sigaction(SIGALRM,&new,NULL); return usleep;}int main(){ while(1){ mysleep(3); printf("sleep over\n"); } return 0;}
运行结果:
结果分析:
首先程序如我们所预期的一样,能看到的效果是每隔三秒执行有一次,看似实现了sleep函数的功能,再此对于handler方法采用的是打印其signum,但是上面的代码存在线程安全问题,当不能执行流来运行,就会因为重入问题导致程序结果出现我们所不期待的结果。
竟态条件
上面代码问题的根本原因是系统运行的时序(Timing)并不像我们写程序时所设想的那样。虽然alarm(times)紧接着的下一行就是pause(),但是无法保证pause()一定会在调用alarm(times)之后的times秒之内被调用。由于异步事件在任何时候都有可能发生(这里的异步事件指出现更高优先级的进程),如果我们写程序时考虑不周密,就可能由于时序问题而导致错误,这叫做竞态条件 (Race Condition)。
sigsuspend
#include <signal.h>int sigsuspend(const sigset_t *mask);
说明:和pause一样,sigsuspend没有成功返回值,只有执行了一个信号处理函数之后sigsuspend才返回,返回值为-1,errno设置为EINTR。调用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时解除对某个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。
规避竞态条件的mysleep实现:
//避免静态条件的mysleep实现#include<stdio.h>#include<signal.h>#include<unistd.h>void handler(int sig){ printf("my sig is %d\n",sig);}int mysleep(int time){ struct sigaction new,old; sigset_t newmask,oldmask,suspmask; int usleep=0; new.sa_handler=handler; sigemptyset(&new.sa_mask); new.sa_flags=0; sigaction(SIGALRM,&new,&old); sigemptyset(&newmask); sigaddset(&newmask,SIGALRM); sigprocmask(SIG_BLOCK,&newmask,&oldmask); alarm(time); suspmask=oldmask; sigdelset(&suspmask,SIGALRM); sigsuspend(&suspmask); usleep=alarm(0); sigaction(SIGALRM,&old,NULL); sigprocmask(SIG_SETMASK,&oldmask,NULL); return usleep;}int main(){ while(1){ mysleep(3); printf("sleep over\n"); } return 0;}
运行结果:
结果说明:
首先代码运行起来的现象还是和上面没有什么区别,不过和上面普通版的mysleep实现相比:
如果在调用my_sleep函数时SIGALRM信号没有屏蔽:
1)调用sigprocmask(SIG_BLOCK,&newmask, &oldmask)时,屏蔽SIGALRM。
2)调用sigsuspend(&suspmask)时,解除对SIGALRM的屏蔽,然后挂起等待。
3)SIGALRM递达后suspend返回,自动恢复原来的屏蔽字,也就是再次屏蔽SIGALRM。
4)调用sigprocmask(SIG_SETMASK, &oldmask, NULL)时,再次解除对SIGALRM的屏蔽。
- 信号捕获之pause函数和竟态条件(mysleep)
- Linux-MySleep函数实现与竟态条件
- Linux Signal (7): 捕获信号的alarm和pause函数
- [Linux]继续探究mysleep函数(竞态条件)
- 普通版本mysleep和规避竞态条件的mysleep
- Linux 信号之mysleep
- mysleep()的多个版本实现及竟态条件的认知
- 10.10 信号_alarm和pause函数
- 捉拿信号的alarm和pause函数
- apue-alarm和pause函数,关于信号
- Linux环境编程之信号处理(三、利用alarm()和pause()函数实现sleep()函数)
- 线程同步之竟态条件
- 信号之可重入函数、竞态条件
- 1.信号处理之:kill(),alarm(),pause()函数
- linux信号处理之signal、sigaction、alarm、pause函数
- linux 信号 alarm和pause
- UNIX环境高级编程——信号之kill、raise、killpg、alarm、pause、abort、sleep、usleep、nanosleep和setitimer函数
- 编写规避竞态条件的mysleep
- C++各大有名库的介绍(转)
- 给单选按钮选择默认值以及获取单选按钮选择值
- 1125
- 为什么要路由器端口映射
- 动态规划算法——背包问题(Dynamic Programming Algorithm
- 信号捕获之pause函数和竟态条件(mysleep)
- CANopen通信之NMT通信
- Oracle导出表结构至Excel
- Innosetup 创建快速运行栏快捷方式 win7 win 8 win10 均不可用
- 关于子进程异步等待方式(SIGCHLD信号)
- 在函数内部打印函数名称
- jQuery发送ajax请求并把得到的数据存放到数组中并判断是否有某值
- Linux Shell脚本字符串命令中的管道符处理
- Python字符串、时间戳、datetime时间相关转换