title: 进程控制
date: 2019/11/30 15:13:40
toc: true
进程控制
fork后的资源
-
缓冲区,比如
printf
等资源没有fflush
,缓冲区会被复制到子进程中 -
父进程重定向后,子进程也被重定向.父进程的文件描述符都被复制到子进程,类似dup,共享文件表项
-
子进程继承的属性
-
子进程不继承的属性
fork的后续操作
- 类似网络服务器多进程,子进程对应一个客户端
- 执行
exec
,执行另外的函数,这种情况下进入exec
后原来的文件表项我们用不到了,所以一般会在文件描述符设置标志close-on-exec
,也就是这个文件描述符在进入exec
后被关闭,但在fork
和exec
间依然可用
vfork
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-------
");
printf("I am parrent
");
pid_t pid;
if((pid=fork())==0) //child
{
while(1)
{
printf("%4d: I am child,pid=%d,ppid=%d
",i++,getpid(),getppid());
sleep(5);
}
}
else
{
while(1)
{
printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d
",i++,getpid(),getppid());
sleep(5);
}
}
}
void parrent_exit_first(void)
{
int i=0;
printf("-------parrent_exit_first-------
");
printf("I am parrent
");
pid_t pid;
if((pid=fork())==0) //child
{
while(1)
{
printf("%4d: I am child,pid=%d,ppid=%d
",i++,getpid(),getppid());
sleep(3);
}
}
else
{
while(1)
{
static int num=0;
if(num++ >10)
{
printf("parrent_exit_first,pid=%d,ppid=%d
",getpid(),getppid());
return ;
}
printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d
",i++,getpid(),getppid());
sleep(3);
}
}
}
void child_exit_first(void)
{
int i=0;
printf("-------child_exit_first-------
");
printf("I am parrent
");
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
",getpid(),getppid());
return ;
}
printf("%4d: I am child,pid=%d,ppid=%d
",i++,getpid(),getppid());
sleep(3);
}
}
else
{
while(1)
{
printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d
",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-------
");
printf("I am parrent
");
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
",getpid(),getppid());
return ;
}
printf("%4d: I am child,pid=%d,ppid=%d
",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
");
}
printf("%4d: I am parrent_exit_first,pid=%d,ppid=%d
",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
", (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);
}