zoukankan      html  css  js  c++  java
  • Linux进程理解与实践(二)僵尸&孤儿进程 和文件共享

    孤儿进程与僵尸进程

    孤儿进程:

       如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程。(注:任何一个进程都必须有父进程)

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <errno.h>  
    4. #include <unistd.h>  
    5.   
    6. int main()  
    7. {  
    8.     pid_t pid;  
    9.     //创建一个进程  
    10.     pid = fork();  
    11.     //创建失败  
    12.     if (pid < 0)  
    13.     {  
    14.         perror("fork error:");  
    15.         exit(1);  
    16.     }  
    17.     //子进程  
    18.     if (pid == 0)  
    19.     {  
    20.         printf("I am the child process. ");  
    21.         //输出进程ID和父进程ID  
    22.         printf("pid: %d ppid:%d ",getpid(),getppid());  
    23.         printf("I will sleep five seconds. ");  
    24.         //睡眠5s,保证父进程先退出  
    25.         sleep(5);  
    26.         printf("pid: %d ppid:%d ",getpid(),getppid());  
    27.         printf("child process is exited. ");  
    28.     }  
    29.     //父进程  
    30.     else  
    31.     {  
    32.         printf("I am father process. ");  
    33.         //父进程睡眠1s,保证子进程输出进程id  
    34.         sleep(1);  
    35.         printf("father process is  exited. ");  
    36.     }  
    37.     return 0;  
    38. }  

    僵尸进程:

       如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵尸进程。

    1. #include <stdio.h>  
    2. #include <unistd.h>  
    3. #include <errno.h>  
    4. #include <stdlib.h>  
    5.   
    6. int main()  
    7. {  
    8.     pid_t pid;  
    9.     pid = fork();  
    10.     if (pid < 0)  
    11.     {  
    12.         perror("fork error:");  
    13.         exit(1);  
    14.     }  
    15.     else if (pid == 0)  
    16.     {  
    17.         printf("I am child process.I am exiting. ");  
    18.         exit(0);  
    19.     }  
    20.     printf("I am father process.I will sleep two seconds ");  
    21.     //等待子进程先退出  
    22.     sleep(2);  
    23.     //输出进程信息  
    24.     system("ps -o pid,ppid,state,tty,command");  
    25.     printf("father process is exiting. ");  
    26.     return 0;  
    27. }  

    <defunct>僵尸进程

    孤儿进程由init处理,并不会有什么危害。但是僵尸进程的大量存在会占用PID等资源,可能会导致系统无法产生新的进程。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。  如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理

    避免僵尸进程

     通过信号机制

     子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。测试程序如下所示:

    1. //示例: 避免僵尸进程  
    2. int main(int argc, char *argv[])  
    3. {  
    4.     signal(SIGCHLD, SIG_IGN);  
    5.     pid_t pid = fork();  
    6.     if (pid < 0)  
    7.         err_exit("fork error");  
    8.     else if (pid == 0)  
    9.         exit(0);  
    10.     else  
    11.     {  
    12.         sleep(50);  
    13.     }  
    14.     exit(0);  
    15. }  

    文件共享

       父进程的所有文件描述符都被复制到子进程中, 就好像调用了dup函数, 父进程和子进程每个相同的打开文件描述符共享一个文件表项(因此, 父子进程共享同一个文件偏移量);


    1. //根据上图: 理解下面这段程序和下图的演示  
    2. int main(int argc, char *argv[])  
    3. {  
    4.     signal(SIGCHLD, SIG_IGN);  
    5.   
    6.     int fd = open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);  
    7.     if (fd == -1)  
    8.         err_exit("file open error");  
    9.   
    10.     cout << "We Don`t flash memory ";  
    11.   
    12.     char buf[BUFSIZ];  
    13.     bzero(buf, sizeof(buf));  
    14.   
    15.     pid_t pid = fork();  
    16.     if (pid < 0)  
    17.         err_exit("fork error");  
    18.     else if (pid > 0)  
    19.     {  
    20.         strcpy(buf, "Parent...");  
    21.         write(fd, buf, strlen(buf));  
    22.         close(fd);  
    23.         cout << "fd = " << fd << endl;  
    24.         exit(0);  
    25.     }  
    26.     else if (pid == 0)  
    27.     {  
    28.         strcpy(buf, "Child...");  
    29.         write(fd, buf, strlen(buf));  
    30.         close(fd);  
    31.         cout << "fd = " << fd << endl;  
    32.         exit(0);  
    33.     }  
    34. }  
    结果是fd(文件描述符)的值相等。这说明父子进程共享同一个文件描述符,当然文件偏移量等信息也是共享的。 

    fork与vfork的区别

    1. fork子进程拷贝父进程的数据段(但是现在提供了写时复制技术,只有当子进程真正需要写内存时,才复制出该内存的一段副本),因此,在父进程/子进程中对全局变量所做的修改并不会影响子进程/父进程的数据内容.

        vfork子进程与父进程共享数据段,因此父子进程对数据的更新是同步的;

    2. fork父、子进程的执行次序是未知的,取决于操作系统的调度算法

        vfork:子进程先运行,父进程后运行

    3. 如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork,但是你在vfork后执行其它语句却是非常危险的,因为很容易和父进程产生冲突。

    1. #include <unistd.h>  
    2. #include <stdio.h>  
    3. int main(void)  
    4. {  
    5.     pid_t pid;  
    6.     int count = 0;  
    7.     pid=vfork();  
    8.     count++;  
    9.     printf("count=%d ",count);  
    10.     return 0;  
    11. }  
    在学习linux进程编程的时候遇到一个问题,就是使用vfork()函数以后本以为下面会打印出1和2,但是结果却出人意料。

    打印出的结果是:

    count=1
    count=1
    Segmentation fault

    出现了段错误,经过查证得知,vfork()创建子进程成功后是严禁使用return的,只能调用exit()或者exec族的函数,否则后果不可预料,在main函数里return和exit()效果一样是有前提的:没有调用vfork。

    (如果return处什么都没有也会出现段错误,结果如下

    count=1
    count=9
    Segmentation fault

    )

  • 相关阅读:
    [Keyence Programming Contest 2020 E] Bichromization
    [Gym101821B] LIS vs. LDS
    [Ynoi2010]iepsmCmq【数据结构】
    【集训队作业2018】喂鸽子
    【集训队作业2018】复读机
    【NOI2015】荷马史诗
    【IOI2018】组合动作
    【清华集训2017】榕树之心
    【清华集训2016】Alice和Bob又在玩游戏
    1209F
  • 原文地址:https://www.cnblogs.com/Zoran-/p/5819288.html
Copyright © 2011-2022 走看看