- 上机环境linux mint下 Qt5.11
- 一例孤儿进程代码的演示
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<unistd.h> #include<sys/types.h> #include<fcntl.h> int main() { pid_t pid; pid =fork(); if(pid==0) { while(1) { printf("i'm child=%d, parent=%d ",getpid(),getppid()); sleep(1); } } else if(pid==-1) { perror("process failed!"); exit(1); } else { printf("i'm the master process %d ",getpid()); sleep(10); printf("master process %d died ",getpid()); } return 0; }
输出结果:
由此可见,进程13345的父进程结束后,变为孤儿进程,其父进程转为1365
- 给僵尸进程下的定义
子进程结束时,父进程会受到SIGCHILD信号。如果没有收到,也没有执行wait()子进程,那么子进程虽然终止,但还是会在内核中占有表项(PCB依然存在),此时子进程就被称作僵尸进程
- 避免僵尸进程的方法
父进程要处理SIGCHILD信号忽略(忽略也是种处理哦)或者捕捉它,或者等待子进程结束。
如果父进程先于子进程结束,那么子进程的终止将转交给init进程处理
- waitpid((int)子进程号,(int)状态码,阻塞模式)
#include <stdio.h> #include<sys/wait.h> #include<stdlib.h> #include<signal.h> #include<unistd.h> int main() { pid_t pid; int status; int retval; pid=fork(); if(pid==-1) { perror("fork"); exit(EXIT_FAILURE); } else if(pid==0) { puts("child process launched "); sleep(3000); exit(EXIT_SUCCESS); } else{ if(waitpid(pid,&status,WNOHANG)==0)//exit process without block { retval=kill(pid,SIGKILL);//跟信号有关的系统调用,一如kill if(retval) { puts("kill failed"); perror("failed"); } else { printf("%d has been killed ",pid); } } } }
- waitpid函数第一个参数取值范围详解
关键词:等待回收 pid<-1 如果子进程的组进程号是pid的绝对值,那么这些子进程都会被父进程等待回收 pid=-1等待任何子进程相当于wait() pid=0进程组码与目前进程相同的子进程 pid>0识别码为pid的子进程
- sigaction
struct sigaction { void (*sa_handler)(int);//信号处理函数1 void(*sa_sigaction)(int,siginfo_t *,void*);//信号处理函数2 sigset_t sa_mask;//信号处理函数执行期间需要屏蔽的信号,确保该信号不会再发生,例如正在处理信号A,如果又收到信号A,那么视同就是当前处理的这个新号A,这时,新到的信号A放入进程的信号掩码sa_mask int sa_flags;//指定信号处理行为,当包含SA_SIGINFO时,使用该系处理函数,否则使用SA_HANDLER系列处理函数 void (*sa_restorer)(void);//已废弃不再使用,仅仅用作占位 }
- sa_flags 是下列信号处理行为的“按位或”组合
SA_START 被信号打断的系统调用重新发起
SA_NOCLDSTOP父进程在他的子进程暂停或继续运行时不会收到SIGCHILD信号
SA_NOCLDWAIT使父进程在子进程退出时不会收到SIGCHILD信号,这种情况下子进程不会成为僵尸进程
SA_NODEFER对信号的屏蔽无效,在信号处理期间仍能发出这个新号
SA_SIGINFO使用sa_sigaction而不是sa_handler作为信号处理函数
- 用例:sigaction函数,使用SA_HANDLER方法---这意味着,我们使用自定义的函数来处理信号
- 自定义信号处理函数sig_usr
static void sig_usr(int signum) { if(signum==SIGUSR1) { puts("sigusr1 received "); } else if(signum==SIGUSR2) { puts("sigusr2 received "); } else { puts("bad luck! "); } }
- 主函数调用
int main() { int n;//n用于返回read()调用后的返回值 struct sigaction sa_method; char buf[512];//栈上声明个字符数组变量,用于存放输入的命令 sa_method.sa_flags=0; sa_method.sa_handler=sig_usr;//表示使用自定义的信号处理函数 //SIGUSR1 SIGUSR2是系统预留给程序员玩的两个信号 sigaction(SIGUSR1,&sa_method,NULL); sigaction(SIGUSR2,&sa_method,NULL); printf("当前进程号是:%d ",getpid()); while(1) { //读取文件描述符STDIN_FILENO //耐人寻味的read用法,参数一是要读取的文件描述符,参数二是要读取的数据类型大小,代码中的buf是字符数组的首元素大小,511是指一次最多可以读取511个首元素大小的量 if((n=read(STDIN_FILENO,buf,511))==-1)//n如果大于0,是返回读取的字节数,-1代表读取失败,0代表没有读取到任何东西 { if(errno==EINTR) { printf("读取出现问题,被信号中断 "); } } else { buf[n]='