进程:占用内存空间的正在运行的程序。
下面通过这一段程序理解多进程:
fork.c
//父进程:fork返回子进程ID,子进程:返回0 //最终运行结果:父进程:gval=11,lval=26; //子进程:gval=12,lval=25; #include <stdio.h> #include <unistd.h> #include <boost/graph/graph_concepts.hpp> int gval=10; int main(void) { int lval=20; lval+=5; gval++; pid_t pid=fork(); //发生复制点 if(pid==0) gval++; else lval++; return 0; }
僵尸进程:exit和return返回的值会给操作系统,而操作系统不会销毁子进程,直到把这些值传给该子进程的父进程。
zombie.c
//在父进程休眠的30s时间里,子进程会变成僵尸进程 //操作系统不会销毁子进程,直到父进程获得子进程的结束状态值 #include <stdio.h> #include <unistd.h> int main(int argc, char *argv[]) { pid_t pid=fork(); if(pid==0) puts("child process"); else { printf("child process ID:%d \n", pid); sleep(30); //父进程休眠30s } if(pid==0) puts("End child process"); else puts("End parent process"); return 0; }
销毁僵尸进程方法1:利用wait函数(父进程主动请求获取子进程的返回值)
//利用wait函数终止子进程 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main(void) { int status; pid_t pid=fork(); //创建子进程1 if(pid==0) return 3; else { printf("child pid:%d \n", pid); pid=fork(); //创建子进程2 if(pid==0) exit(7); else { printf("child pid:%d \n", pid); //销毁第一个子进程 wait(&status); if(WIFEXITED(status)) printf("child send1: %d \n", WEXITSTATUS(status)); //销毁第二个子进程 wait(&status); if(WIFEXITED(status)) printf("child send1: %d \n", WEXITSTATUS(status)); sleep(30); //父进程休眠30s } } return 0; }
方法2:利用waitpid函数(wait会引起阻塞,而waitpid不会)
//使用wait函数会阻塞程序直到有子进程终止 //waitpid可以避免这个问题 #include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main(void) { int status; pid_t pid=fork(); if(pid==0) { sleep(15); return 24; } else { //WNOHANG:没有终止的子进程不会阻塞程序,而会返回0并退出函数 while(!waitpid(pid, &status, WNOHANG)) { sleep(3); puts("sleep 3s"); } if(WIFEXITED(status)) printf("child send: %d \n", WEXITSTATUS(status)); } return 0; }
方法3:利用信号处理技术消灭僵尸进程
//利用信号处理技术消灭僵尸进程 //信号处理:在特定事件发生时由操作系统向进程发送信号, //为了响应信号,进程执行与信号相关的自定义操作。 //使用sigaction函数 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> //一旦有子进程结束就调用这个函数 void read_childproc(int sig) { int status; pid_t id=waitpid(-1, &status, WNOHANG); if(WIFEXITED(status)) { printf("remove proc id: %d \n", id); printf("child send: %d \n", WEXITSTATUS(status)); } } int main(void) { pid_t pid; struct sigaction act; act.sa_handler=read_childproc; sigemptyset(&act.sa_mask); act.sa_flags=0; sigaction(SIGCHLD, &act, 0); pid=fork(); if(pid==0) //子进程执行区域 { puts("Im child process1"); sleep(10); return 12; } else //父进程执行区域 { printf("child proc id: %d \n", pid); pid=fork(); if(pid==0) { puts("Im child process2"); sleep(10); exit(24); } else { int i; printf("child proc id: %d \n", pid); for(i=0;i<5;i++) { puts("wait..."); sleep(5); } } } return 0; }