linux中fork--子进程是从哪里开始运行

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。此时,两个进程都从fork开始往下执行,只是pid不同。
   
有人可能疑惑为什么不是从#include处开始复制代码的?

看下图:

      上图表示一个含有fork的程序,而fork语句可以看成将程序切为A、B两个部分。然后整个程序会如下运行:

      step1、设由shell直接执行程序,生成了进程P。P执行完Part. A的所有代码。

      step2、当执行到pid = fork();时,P启动一个进程Q,Q是P的子进程,和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的当前值。

      step3、在P进程中,fork()将Q的PID返回给变量pid,并继续执行Part. B的代码。

      step4、在进程Q中,将0赋给pid,并继续执行Part. B的代码。

      这里有三个点非常关键:

      1、P执行了所有程序,而Q只执行了Part. B,即fork()后面的程序。(这是因为Q继承了P的PC-程序计数器)

      2、Q继承了fork()语句执行时当前的环境,而不是程序的初始环境。

      3、P中fork()语句启动子进程Q,并将Q的PID返回,而Q中的fork()语句不启动新进程,仅将0返回。

#include <unistd.h>
#include <sys/types.h>

main ()
{
         pid_t pid;
         printf("hello!\n"); 
         pid=fork();

         if (pid < 0)
                 printf("error in fork!");
         else if (pid == 0)
                 printf("i am the child process, my process id is %d\n ",getpid());
         else
                 printf("i am the parent process, my process id is %d\n",getpid());

         printf("bye!\n");
}

这里可以看出parent process执行了printf("hello!\n");  而child process 没有执行printf("hello!\n"); 

有一个让人很迷惑的例子:

#include <unistd.h>
#include <sys/types.h>

main ()
{
         pid_t pid;
         printf("fork!");    //printf("fork!\n")

         pid=fork();

         if (pid < 0)
                 printf("error in fork!\n");
         else if (pid == 0)
                 printf("i am the child process, my process id is %d\n",getpid());
         else
                 printf("i am the parent process, my process id is %d\n",getpid());
}


此时打印输出了两个fork!这不免让人以为是child process从#include处开始执行,所以也执行了printf("fork!"); 语句。

其实不然,出现这种问题的原因在于:

这就跟Printf的缓冲机制有关了,printf某些内容时,操作系统仅仅是把该内容放到了stdout的缓冲队列里了,并没有实际的写到屏幕上 。但是,只要看到有\n, 则会立即刷新stdout,因此就马上能够打印了.

mian函数(parent process)运行了printf("fork!") 后, "fork!"仅仅被放到了缓冲里,再运行到fork时,缓冲里面的 AAAAAA 被子进程(child process)继承了,因此在子进程度stdout缓冲里面就也有了"fork!"。所以,你最终看到的会是 "fork!" 被printf了2次!!!!
mian函数(parent process)运行 printf("fork!\n")后,"fork!" 被立即打印到了屏幕上,之后fork到的子进程(child process)里的stdout缓冲里不会有"fork!"内容 因此你看到的结果会是"fork!" 被printf了1次!!!!


  • 28
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
进程编程是一种应用在Unix/Linux系统的编程方法,其一个重要的概念就是fork(分叉)。 在Linuxfork是一个系统调用,它创建一个新的进程。通过fork,父进程可以生成一个与自己完全相同的子进程。父进程和子进程之间的唯一区别在于它们的进程ID不同,其他方面都是一模一样的。 fork的作用是允许一个进程创建一个与自己共享资源的进程,但是拥有独立的执行空间。这样可以避免不同进程之间相互影响和干扰。 在使用fork的过程,操作系统会将父进程的所有信息(包括代码、数据、打开的文件描述符等)拷贝一份给子进程。然后,父进程和子进程会从fork调用的返回值得到不同的结果。在父进程,返回的是子进程的进程ID;在子进程,返回的是0。这样,父进程就可以根据fork的返回值来判断自己是父进程还是子进程,从而进行不同的操作。 在实际的编程,可以通过fork来实现各种不同的功能。比如,可以通过fork创建一个子进程来进行并发执行,提高程序的运行效率。另外,可以通过fork来创建一个子进程来执行一段代码,然后通过父进程来等待子进程的结束并处理子进程的结果。 总之,进程编程fork是一个非常重要且常用的概念,它提供了创建和管理进程的能力,为程序的并发执行和资源的管理提供了可能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值