title: 进程控制
date: 2019/11/30 15:13:40
toc: true
---
进程控制
fork后的资源
缓冲区,比如
printf
等资源没有fflush
,缓冲区会被复制到子进程中父进程重定向后,子进程也被重定向.父进程的文件描述符都被复制到子进程,类似dup,共享文件表项
子进程继承的属性
子进程不继承的属性
fork的后续操作
- 类似网络服务器多进程,子进程对应一个客户端
- 执行
exec
,执行另外的函数,这种情况下进入exec
后原来的文件表项我们用不到了,所以一般会在文件描述符设置标志close-on-exec
,也就是这个文件描述符在进入exec
后被关闭,但在fork
和exec
间依然可用
vfork
https://www.cnblogs.com/1932238825qq/p/7373443.html
vfork
的诞生就是给exec
使用,也就是创建一个全新的进程用的
fork
是 创建一个子进程,并把父进程的内存数据copy到子进程中。vfork
是 创建一个子进程,并和父进程的内存数据share一起用。保证子进程先执行。当子进程调用exit()或exec()后,父进程往下执行
注意
结束子进程的调用是exit()而不是return,如果你在vfork中return了,那么,这就意味main()函数return了,注意因为函数栈父子进程共享,所以整个程序的栈就跪了。
总结
不用就好了,哈哈
exit
退出状态与终止状态
退出状态: main或者
exit
,_exit
,_Exit
的返回值,在最后调用_exit
时转换退出状态为终止状态终止状态,异常终止的原因
为什么需要僵死进程
子进程退出,父进程还没处理的.如果父进程先挂,则子进程(孤儿进程)被init收养了
父进程可能需要了解子进程的退出状态信息,因此系统必须提供这样的服务或者功能
当一个进程终止时,内核会检查所有的活动进程,也会检查所有的僵尸
孤儿进程不会变成僵尸进程,因为init会用wait函数来获得其状态也就是如果子进程终止 但是父进程不处理,那么僵死进程就一直存在如果父先于子挂了,子会变为孤儿进程,由init处理
https://www.cnblogs.com/sinpo828/p/10913249.html
写代码看看
#demo1 # 刚开始两个进程都在 reallin@ubuntu:/work/pan/apue/study$ ps -ef | grep exe reallin 4029 2610 0 19:17 pts/2 00:00:00 ./exe reallin 4030 4029 0 19:17 pts/2 00:00:00 ./exe # 父进程退出,子进程变成孤儿进程,由init 接管 reallin@ubuntu:/work/pan/apue/study$ ps -ef | grep exe reallin 4030 1 0 19:17 pts/2 00:00:00 ./exe #demo2 子进程先退出 # 刚开始两个进程都在 reallin@ubuntu:/work/pan/apue/study$ ps aux | grep exe reallin 4479 0.0 0.0 1048 4 pts/2 S+ 19:25 0:00 ./my_tets_exe reallin 4480 0.0 0.0 1048 56 pts/2 S+ 19:25 0:00 ./my_tets_exe # 僵尸进程产生 Z+ reallin@ubuntu:/work/pan/apue/study$ ps aux | grep exe reallin 4479 0.0 0.0 1048 4 pts/2 S+ 19:25 0:00 ./my_tets_exe reallin 4480 0.0 0.0 0 0 pts/2 Z+ 19:25 0:00 [my_tets_exe] <defunct>
extern "C" { #include "apue.h" } #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> void together(void) { int i=0; printf("-------parrent_exit_first-------\n"); printf("I am parrent\n"); pid_t pid; if((pid=fork())==0) //child { while(1) { printf("%4d: I am child,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(5); } } else { while(1) { printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(5); } } } void parrent_exit_first(void) { int i=0; printf("-------parrent_exit_first-------\n"); printf("I am parrent\n"); pid_t pid; if((pid=fork())==0) //child { while(1) { printf("%4d: I am child,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } else { while(1) { static int num=0; if(num++ >10) { printf("parrent_exit_first,pid=%d,ppid=%d\n",getpid(),getppid()); return ; } printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } } void child_exit_first(void) { int i=0; printf("-------child_exit_first-------\n"); printf("I am parrent\n"); pid_t pid; if((pid=fork())==0) //child { while(1) { static int num=0; if(num++ >10) { printf("childt_exit_first,pid=%d,ppid=%d\n",getpid(),getppid()); return ; } printf("%4d: I am child,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } else { while(1) { printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } } int main(int argc, char const *argv[]) { ///together(); //parrent_exit_first(); child_exit_first(); return 1; }
消除这个僵尸进程
怎么清理这个僵尸进程呢? 使用wait系列的函数,这个函数就不会看到僵尸状态的子进程了
void child_exit_first_but_wait(void) { int i=0; printf("-------child_exit_first-------\n"); printf("I am parrent\n"); pid_t pid; if((pid=fork())==0) //child { while(1) { static int num=0; if(num++ >5) { printf("childt_exit_first,pid=%d,ppid=%d\n",getpid(),getppid()); return ; } printf("%4d: I am child,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } else { while(1) { pid_t pp=wait(NULL); if(pp==pid) { printf("I am parent, I know my child has gone\n"); } printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d\n",i++,getpid(),getppid()); sleep(3); } } }
子进程先结束,但是父进程不去管也不产生僵尸进程
- 子进程先结束,父进程需要wait才能避免僵尸进程
- 父进程先结束,没有问题,只是孤儿进程
- 但是如何让父进程和子进程独立?
这里fork了两次,实际的子进程由第一个child创建,第一个child立马退出,第二个child由init接管
#include "apue.h" #include <sys/wait.h> int main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) /* first child */ { if ((pid = fork()) < 0) err_sys("fork error"); else if (pid > 0) exit(0); /* parent from second fork == first child */ /* * We’re the second child; our parent becomes init as soon * as our real parent calls exit() in the statement above. * Here’s where we’d continue executing, knowing that when * we’re done, init will reap our status. */ sleep(2);//-----这里确保first child 先结束 printf("second child, parent pid = %ld\n", (long)getppid()); exit(0); } if (waitpid(pid, NULL, 0) != pid) /* wait for first child */ err_sys("waitpid error"); /* * We’re the parent (the original process); we continue executing, * knowing that we’re not the parent of the second child. */ exit(0); }