微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

理解父子进程执行顺序

如何解决理解父子进程执行顺序

据我所知,子进程先执行。为什么父进程先于子进程执行,父进程又被执行?执行过程是如何从父级到子级再到父级的?为什么要关闭管道?我尝试了没有关闭管道语句的代码,但得到了相同的输出

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void main(){
    
    int P1P2[2];
    int P2P1[2];
    pipe(P1P2);
    pipe(P2P1);
    int x,y;
    if(fork()){  // father
    
        close(P1P2[0]);
        close(P2P1[1]);
        printf("Enter one integer:");
        scanf("%d",&x);
        write(P1P2[1],&x,sizeof(x));
        read(P2P1[0],&y,sizeof(y));
        printf("Multiplication is %d\n",y);
    
    }
    else{   //  Child
        close(P1P2[1]);
        close(P2P1[0]);
        read(P1P2[0],sizeof(x));
        y = x*x;
        write(P2P1[1],sizeof(y));
        
    }
}

输出

abbas@abbas-VirtualBox:~/Desktop$ ./simplle
Enter one integer:4
Multiplication is 16

解决方法

调用fork后,有两个进程相互独立运行。处理器在它们之间切换,就像在其他单独的进程中一样,因此您不会总是得到相同的行为。 如果您确实希望父级等待子级完成,则可以使用 waitpid。

,
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    
    int P1P2[2];
    int P2P1[2];
    pipe(P1P2);
    pipe(P2P1);
    int x,y;
    if( fork() > 0 ){  // parent
        close(P1P2[0]);
        close(P2P1[1]);
        printf("Enter one integer:");
        scanf("%d",&x);
        write(P1P2[1],&x,sizeof(x)); /* (2) */
        read(P2P1[0],&y,sizeof(y));  /* (3) */
        printf("Multiplication is %d\n",y);
    } else {   //  Child (or pipe error)
        close(P1P2[1]);
        close(P2P1[0]);
        read(P1P2[0],sizeof(x)); /* (1) */
        y = x*x;
        write(P2P1[1],sizeof(y));  /* (4) */
    }  
}

假设孩子在 fork 之后立即运行,而父母没有。子进程将在 (1) 处的 read 上阻塞,等待数据。由于没有数据,它将产生cpu。在未来的某个时刻,父进程将被调度并执行 printfscanfwrite。在父级在 (2) 处写入管道后,子级或父级可以以任何顺序执行。最终,父进程将在 (3) 处阻塞读取,并且在子进程在 (4) 处写入之前将无法继续。所以管道可以同步进程。

,

据我所知,子进程先执行。为什么父进程先于子进程执行,父进程又被执行?执行过程是如何从父级到子级再到父级的?为什么要关闭管道?我尝试了没有关闭管道语句的代码,但得到了相同的输出。

你的知识不正确。你不知道谁先被安排,是父母还是孩子。这两种情况都可能发生。在系统调用检查所有可能的错误后,父进程通常可以自由运行,而子进程仍然需要构建一个完整的环境才能运行。所以父级先跑是很有可能的。

执行通常是这样的。父进程调用 fork(),后者又切换到内核模式。在这里,父进程(在任何地方仍然没有子进程)检查创建子进程所需的所有条件、足够的资源、未超出限制等,如果一切正常,那么它会在进程表中创建一个新的进程条目。完成后,父内核代码拥有开始运行第二个内核线程并启动它的所有元素,以执行 fork 调用的第二部分,而第一个(父进程)已经具有系统的返回代码调用并准备运行(这意味着子进程将被执行,不会失败,但它不需要立即执行)。从这点开始,父进程可以从内核模式返回子进程 pid 并继续,而子内核仍然需要构建足够的上下文来运行和被调度。这可能发生得非常快,甚至在调度程序有时间再次重新调度父级之前,因此结论是您不知道哪个是先继续执行用户代码。

关于你的第二个问题,从 fork() 开始的执行顺序取决于很多实际上不可预测的事情。两者都是不同的进程,只要系统允许它们继续,就会立即执行。

关于管道的关闭,您可以做也可以不做....随您的喜好...但是管道可以将所有数据从写入器进程传递给读取器,直到管道获得它的last close(2) 当你 fork() 时,系统通过了有两个管道,有四个文件描述符,有 4 个(两个在父级上,两个在子级上),总共有八个文件描述符(四个读取器和四个写入器描述符,每个进程两个)(这意味着两个写入器,父进程和子进程,需要为读取器关闭(2)管道的写入端——同样,父进程和子进程-- 接收相应的 EOF,表明另一端已关闭其一侧)这与您无关(我的意思是,没有显示任何区别)因为 您将协议限制为每个消息中只有一个消息方向,并且没有需要等待的 EOF 条件......但是尝试扩展您的示例代码以从管道中读取,直到它关闭它,并且您会看到不同之处(在这种情况下,如果没有关闭编写器端,您的进程将阻塞等待输入,并且没有收到输入,因为另一个进程已关闭描述符并且唯一等待输入的进程是唯一的进程可以在上面写字)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。