进程控制


title: 进程控制
date: 2019/11/30 15:13:40
toc: true

进程控制

fork后的资源

  1. 缓冲区,比如printf等资源没有fflush,缓冲区会被复制到子进程中

  2. 父进程重定向后,子进程也被重定向.父进程的文件描述符都被复制到子进程,类似dup,共享文件表项

    mark

mark

  1. 子进程继承的属性

    mark

  2. 子进程不继承的属性

    mark

fork的后续操作

  1. 类似网络服务器多进程,子进程对应一个客户端
  2. 执行exec,执行另外的函数,这种情况下进入exec后原来的文件表项我们用不到了,所以一般会在文件描述符设置标志close-on-exec,也就是这个文件描述符在进入exec后被关闭,但在forkexec间依然可用

vfork

https://www.cnblogs.com/1932238825qq/p/7373443.html

vfork的诞生就是给exec使用,也就是创建一个全新的进程用的

  • fork 是 创建一个子进程,并把父进程的内存数据copy到子进程中。
  • vfork是 创建一个子进程,并和父进程的内存数据share一起用。保证子进程先执行。当子进程调用exit()或exec()后,父进程往下执行

注意

结束子进程的调用是exit()而不是return,如果你在vfork中return了,那么,这就意味main()函数return了,注意因为函数栈父子进程共享,所以整个程序的栈就跪了。

总结

不用就好了,哈哈

exit

mark

退出状态与终止状态

  • 退出状态: 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);
        }
    }

}

子进程先结束,但是父进程不去管也不产生僵尸进程

  1. 子进程先结束,父进程需要wait才能避免僵尸进程
  2. 父进程先结束,没有问题,只是孤儿进程
  3. 但是如何让父进程和子进程独立?

这里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);
}
原文地址:https://www.cnblogs.com/zongzi10010/p/11991481.html