fork后发生了什么——执行流篇

/ 0评 / 0

     首先我们先从这个最基本的问题开始吧,fork为什么”好像返回了两次“?确实只能说好像,因为函数的栈帧上是不可能两个返回动作的,汇编层面决定了压栈出栈的动作值必须是成对的,一个函数永远都只可能返回一次。有两个返回只是表象,执行流被分成两份同样也只是表象,那么本质上是怎么回事呢?


fork函数调用后,创建PCB并填充后,子进程会完全拷贝了父进程的地址空间,栈、堆、代码段自然就都被拷贝了一份,所以答案就是:因为子进程的栈是从父进程那儿拷贝过来,那么其函数的栈帧就是完全相同的两份,不过是各自在各自的函数栈中返回了。父子进程会被我们根据fork的返回值分成两条执行流,子进程之所以是从fork函数之后开始运行的原因当然也就在这了:因为子进程的代码段、上下文环境完全拷贝的父进程,父进程的fork函数返回点在哪儿,子进程就在哪儿,返回后根据我们的代码控制父子就分开了,关于这些若是不理解到这个程度,恐怕很难却理解父子进程里的一些奇怪现象。        再想一个问题,linux进程的执行是由操作系统来进行调度的,那么子进程被fork出来后,是父进程先执行还是子进程先执行呢?        一般情况下我们总是用sleep等操作来保证另一个进程先执行,那么谁先执行是完全不可预料的吗?其实不是,从linux内核2.6.32开始,在默认情况下,父进程将成为fork之后优先调度的对象。采取这种策略的原因很简单:fork是父进程发起的调用,因此fork之后,父进程在CPU中处于活跃的状态,并且其内存管理信息也被置于硬件内存单元的转译后备缓冲器(TLB),所以先调度父进程无论从减少上下文切换、CPU让出等方面都可以提高性能。linux内核从2.6.24开始,内核采用完全公平调度(CFS),用户创建的普通进程,都采用CFS调度策略。对于CFS调度策略,内核提供了如下控制选项:

该值默认是0,表示父进程优先获得调度。如果该值被改为1,子进程会优先获得调度。POSIX标准和linux都没有保证会优先调度父进程,因此在应用中,我们不能对父子进程的执行顺序做任何假设。如果确实需要父子进程的某一特定执行顺序,那么还是得需要进程间的同步手段。

发表评论

电子邮件地址不会被公开。 必填项已用*标注