Linux-MySleep函数实现与竟态条件
2017-08-05 14:18
211 查看
(一) 函数实现的整体框架
1>需要用到的函数接口2>实现的整体过程思路
3>程序运行遇到可能情况的分析
4>优化结果与解决方案
(二)三个主要的函数接口
根据系统内部的sleep函数为基础,通过了解其运行过程,可以使用alarm()函数,pause()函数以及sigaction()函数进行实现。函数参数及返回值
Markdown Extra 表格语法:函数名称 | 参数 | 返回值 |
---|---|---|
alarm() | unsigned int seconds | 返回0或信号响应后剩余时间 |
pause() | void | 只有出错返回值 |
sigaction() | (int signo,const struct sigaction *restrict act,struct sigaction *restrict oact) | 这里不做研究 |
sigaction结构体
struct sigaction {void (*sa_handler)(int);
void (sa_sigaction)(int, siginfo_t , void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
}
信号处理函数可以采用void (sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t , void )。到底采用哪个要看sa_flags中是否设置了SA_SIGINFO位,如果设置了就采用void (*sa_sigaction)(int, siginfo_t , void *),此时可以向处理函数发送附加信息;默认情况下采用void (*sa_handler)(int),此时只能向处理函数发送信号的数值。
sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。
sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号集搁置。
sa_restorer 此参数没有使用。
sa_flags 用来设置信号处理的其他相关操作,下列的数值可用。
sa_flags还可以设置其他标志:
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER :一般情况下, 当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了 SA_NODEFER标记, 那么在该信号处理函数运行时,内核将不会阻塞该信号
mysleep实现代码
#include<stdio.h> #include<signal.h> void myhandler(int sig) {} int mysleep(int timeout) { struct sigaction act,oact; act.sa_handler = myhandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM,&act,&oact); alarm(timeout); pause(); int ret = alarm(0); sigaction(SIGALRM,&oact,NULL); return ret; } int main() { while(1) { printf("mysleep start...\n"); mysleep(3); printf("mysleep success\n"); } return 0; }
执行过程
1)main函数调用mysleep函数。mysleep函数调用sigaction注册了SIGALRM信号的处理函数myhandler。这里的myhandler函数并没有做什么工作,但不能少,因为SIGALRM信号的默认处理是终止进程。2)调用alarm(timeout)设定闹钟。
3)调用pause等待,内核切换到别的进程运行。
4)timeout秒之后,闹钟超时,内核发SIGALRM给这个进程。
5)从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是myhandler。
6)于是切换到用户态执行myhandler函数,进入myhandler函数时SIGALRM信号被自动屏蔽, 从myhandler函数返回时SIGALRM信号自动解除屏蔽。然后自动执行系统调用sigreturn再次进入内核,再返回用户态继续执行进程的主控制流程,即为main函数调用mysleep函数处。
7) pause函数返回-1,然后调用alarm(0)取消闹钟,调用sigaction恢复SIGALRM信号以前的处理动作。
竟态条件
竞态条件(race condition),从多进程间通信的角度来讲,是指两个或多个进程对共享的数据进行读或写的操作时,最终的结果取决于这些进程的执行顺序。pause()函数与sigsuspend()函数的区别
sigsuspend函数是pause函数的增强版。当sigsuspend函数的参数信号集为空信号集时,sigsuspend函数是和pause函数是一样的,可以接受任何信号的中断。但是,sigsuspend函数可以屏蔽信号,接受指定的信号中断。sigsuspend函数=pause函数+指定屏蔽信号
注:信号中断的是sigsuspend和pause函数,不是程序代码。
sigsuspend是否影响sigprocmask屏蔽的信号呢?
影响!sigsuspend使原来的屏蔽信号全部失效,当sigsuspend返回,恢复原来的屏蔽信号。
注意:在sigsuspend函数调用时,会使进程挂起(进入睡眠状态)等待信号的中断,如果没有信号发生,进程会一直挂起,当有信号发生时,但该信号不是sigsuspend函数的信号集中所设置的屏蔽的信号时,sigsuspend会处理该信号,当该信号处理完成后,sigsuspend函数才返回,并执行接下来的代码。
mysleep将pause()函数替换为sigsupend()
#include <unistd.h> #include <signal.h> #include <stdio.h> void myhandler(int sig) {} int mysleep(int timeout) { struct sigaction act, oact; sigset_t newmask, oldmask, suspmask; act.sa_handler = myhandler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGALRM, &act, &oact); sigemptyset(&newmask); sigaddset(&newmask, SIGALRM);//添加SIGALRM信号 sigprocmask(SIG_BLOCK, &newmask, &oldmask); //添加SIGALRM信号屏蔽字 alarm(timeout); suspmask = oldmask; sigdelset(&suspmask, SIGALRM);//删除SIGALRM信号 sigsuspend(&suspmask); //解除对SIGALRM信号的屏蔽同时挂起等待 int ret = alarm(0); sigaction(SIGALRM, &oact, NULL); sigprocmask(SIG_SETMASK, &oldmask, NULL); //对信号屏蔽字复位 return ret; } int main(void) { while(1) { printf("mysleep start\n"); mysleep(3); printf("mysleep success\n"); } return 0; }
相关文章推荐
- [Linux]继续探究mysleep函数(竞态条件)
- Linux下利用条件变量实现读写锁
- Linux下SFTP用户权限设置条件及实现命令
- Linux下利用条件变量实现信号量机制
- 关于linux锁的c++封装 条件锁,读写锁(不同方式实现读写优先)
- 【Linux】mysleep函数---普通版本与规避竞态条件版本
- Linux利用list_head结构实现双向链表
- Linux字符设备驱动(三)-文件操作函数实现
- Linux(Ubuntu版本)下配置samba实现文件夹共享的方法:
- Linux下各类TCP服务实现的源代码
- linux下damon的实现
- linux中head、tail命令的实现
- 【Linux C调试笔记】Linux系统下借助mcheck实现c/c++程序的堆内存异常检查
- Linux下用程序实现统计cpu和内存的利用率
- linux下利用shell脚本实现添加crontab任务
- linux下c++ 实现单例模式
- Linux实现ftp账号同时访问两个目录方法
- Linux 下 php 转DOC转PDF转SWF实现百度的文库预览功能【转】
- Linux线程同步之条件变量
- linux中sqoop实现hive数据导入到mysql