APUE学习笔记—— 信号实现系统sleep和system函数,解决进程竞争实例
来源:互联网 发布:美国人聊天软件 编辑:程序博客网 时间:2024/06/06 12:32
1、实现系统sleep函数
此函数使调用进程被挂起,直到满足下列条件之一:(1)已经经过seconds所指定的墙上时钟时间(2)调用进程捕捉到一个信号并从信号处理程序返回。
以下的可靠实现并没有考虑到两个alarm交互作用的情况
可靠实现如下:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void sig_alarm(){}int sleep_(int seconds){ unsigned int unslept; struct sigaction act,oact; act.sa_handler = sig_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigset_t newmask,suspendmask,oldmask; sigaction(SIGALRM,&act,&oact); sigemptyset(&newmask); sigaddset(&newmask,SIGALRM); sigprocmask(SIG_BLOCK,&newmask,&oldmask); alarm(seconds); suspendmask = oldmask; sigdelset(&suspendmask,SIGALRM); sigsuspend(&suspendmask);//挂起,等待alarm信号 unslept = alarm(0); sigprocmask(SIG_SETMASK,&oldmask,NULL); return unslept;}int main(){ int i; for(i = 0 ; i < 7 ; i ++){ printf("The %dth second.\n",i+1); printf("sleep seconds %d\n",sleep_(2)); } return 0;}
2、实现系统system函数
POSIX.1要求system函数忽略SIGINT和SIGQUIT信号,阻塞SIGCHLD。至于原因书本上写的很清楚。下面是个人理解:
system函数的实现是运用fork and exec,来执行shell指令的,所以父进程在子进程完成之前就不能执行SIGINT和SIGQUIT信号,否则父子进程直接中断了,SIGCHLD信号是子进程完成时告诉父进程的信号,如果在子进程没有完成,父进程是不能捕捉SIGCHLD
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <errno.h>#include <sys/wait.h>int system_(const char *cmdstring){ pid_t pid; int status; struct sigaction ignoreact,saveintact,savequitact; ignoreact.sa_handler = SIG_IGN; sigemptyset(&ignoreact.sa_mask); ignoreact.sa_flags = 0; sigaction(SIGINT,&ignoreact,&saveintact);//saveintact是保存以前的配置,可以参见signal的返回值,所以这里也能用signal函数实现 sigaction(SIGQUIT,&ignoreact,&savequitact); sigset_t chldmask,savemask; sigemptyset(&chldmask); sigaddset(&chldmask,SIGCHLD); sigprocmask(SIG_BLOCK,&chldmask,&savemask); if((pid = fork()) == -1){ status = -1; }else if(pid == 0){ sigaction(SIGINT,&saveintact,NULL);//子程序中可以有SIGINT和SIGQUIT信号,所以这里重新 sigaction(SIGQUIT,&savequitact,NULL); execl("/bin/bash","sh","-c",cmdstring,(char*)0);//下面两句在课本上顺序正好相反,这里我没想明白,我认为是应该在子进程execl完成之后才能释放SIGCHLD信号的捕获 sigprocmask(SIG_SETMASK,&savemask,NULL); _exit(127); }else{ while(waitpid(pid,&status,0) < 0) {//让子进程先执行 if(errno != EINTR){ status = -1; break; }} } sigaction(SIGINT,&saveintact,NULL);//以下是父进程恢复这些信号的捕获(此时子进程已经执行完成) sigaction(SIGQUIT,&savequitact,NULL); sigprocmask(SIG_SETMASK,&savemask,NULL); return status;}int main(){ system_("date"); system_("w"); return 0;}
3、解决进程竞争实力
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <signal.h>static volatile sig_atomic_t sigflag;sigset_t newmask,oldmask,susmask;void print(const char *str,pid_t pid){ printf("pid: %d, ",pid); while(*str != '\0') putc(*str++,stdout); printf("\n");}void sig_usr(int signo){ sigflag = 1;}void tell_child(pid_t pid){ kill(pid,SIGUSR1);}void wait_parent(){ susmask = oldmask;//书本上没有添加这两行代码,个人觉得加上更加严谨点,sleep的实现就用了类似的方法 sigdelset(&susmask,SIGUSR1);//使SIGUSR1信号能使其终止挂起状态 while(sigflag == 0) sigsuspend(&susmask); sigflag = 0; sigprocmask(SIG_SETMASK,&oldmask,NULL);}int main(){ pid_t pid; int status; struct sigaction act,oact; act.sa_handler = sig_usr; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGUSR1,&act,&oact); sigemptyset(&newmask); sigaddset(&newmask,SIGUSR1); sigprocmask(SIG_BLOCK,&newmask,&oldmask); printf("%d, %d\n",newmask,oldmask);//输出newmask和oldmask,我输出的结果是512,0 if((pid = fork()) == -1){ printf("fork error"); exit (-1); }else if(pid == 0){ wait_parent();//等待父进程先输出 print("charactor",getpid()); }else{ print("charactor",getpid()); tell_child(pid); } return 0;}这里可以不使用信号的机制来逐个字母输出试试。
- APUE学习笔记—— 信号实现系统sleep和system函数,解决进程竞争实例
- APUE学习笔记——信号、信号集和进程信号屏蔽字
- APUE学习笔记——10信号——信号接口函数 signal 和 sigaction
- APUE学习笔记——10.18 system函数 与waitpid
- APUE学习笔记——信号
- APUE学习笔记——信号
- APUE学习笔记——10 信号
- 《unix高级环境编程》信号——abort、system和sleep函数
- 《unix高级环境编程》信号——abort、system和sleep函数
- APUE学习笔记(17)-线程和信号
- APUE学习笔记(17)-线程和信号
- APUE 信号学习笔记
- APUE学习笔记——进程环境
- APUE学习笔记——进程控制
- APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause
- 进程同步--信号实现--APUE
- APUE学习笔记——第十章 信号
- apue和unp的学习之旅06——简单引出进程和信号的学习
- 避免物理内存碎片化 - ZONE_MOVABLE
- C语言结构体数组的定义
- HDFS读取副本的选择
- 由replaceAll引发的java.util.regex.PatternSyntaxException错误
- Android左右滑动实现Activity切换类 (整合代码实例)
- APUE学习笔记—— 信号实现系统sleep和system函数,解决进程竞争实例
- android LinearLyaout 布局
- 正则表达式基础知识
- Recursive entry to executePendingTransactions
- 抛弃也是一种才智
- fio使用指南
- 巧用MapReduce+HDFS,海量数据去重的五大策略
- 在线生成CPF
- Python Challenge