Linux(1):fork函数

         ps:每一篇博客仅仅是为了记录学习的过程,并反思总结,如有错误,还望指正


       函数原型:extern __pid_t fork (void) __THROWNL;

       该函数包含于头文件unistd.h中。

       源文件中注释:

              /* Clone the calling process, creating an exact copy.Return -1 for errors, 0 to the new process,

   and the process ID of the new process to the old process.  */

            

           fork()会产生一个子进程。其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码、组代码、环境变量、已打开的文件代码、工作目录和资源限制等。Linux 使用copy-on-write(COW)技术,只有当其中一进程试图修改欲复制的空间时才会做真正的复制动作,由于这些继承的信息是复制而来,并非指相同的内存空间,因此子进程对这些变量的修改和父进程并不会同步。此外,子进程不会继承父进程的文件锁定和未处理的信号。(COW并不那么完美 COW是一种很重要的优化手段,核心是懒惰处理实体资源请求,在多个实体资源之间只是共享资源,起初是并不真正实现资源拷贝,只有当实体有需要对资源进行修改时才真正为实体分配私有资源。但COW技术亦有它的优缺点。

      1.COW技术科减少分配和复制大量资源时带来的瞬间延时,但实际上是将这种延时附加到了后续的操作之中。 

      2.COW技术科减少不必要的资源分配。比如fork进程时,并不是所有的页面都需要复制,父进程的代码段和只读数据段都不被允许修改,所以无需复制。 

       注意,Linux不保证子进程会比父进程先执行或晚执行,因此编写程序时要留意死锁或竞争条件的发生。


       返回值:如果fork()调用成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0。如果fork() 失败则直接返回-1,失败原因存于errno中。失败的原因有三个:

      1) 系统内存不够;

      2) 进程表满(容量一般为200~400);

      3) 用户的子进程太多(一般不超过25个)。

     错误代码:EAGAIN 内存不足;ENOMEM 内存不足,无法配置核心所需的数据结构空间。

        fork创建的新进程被称为子进程(child process。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )

    举个例子:

   

    执行结果为:

   

    fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,因为子进程是父进程的副本,所以它拥有父进程数据空间、栈和堆的副本,它们并没有共享这些存储空间,它们只共享正文段。 但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。

   

    执行结果:

   

    由此看出,子进程的值发生了改变,可以说明,它们并不是共享的。

    再来看下变量的地址:

   

    执行结果:

   

    由结果可以看出,变量地址是一样的!!!内容却不一样,因为打印的变量的地址都是逻辑空间, 对于父子进程,它们的逻辑空间一样,都是虚拟地址,但是物理空间还是不同的。每个进程都有独立的4G的虚拟地址空间,映射到不同的物理空间。比如我现在同时运行两个进程,他们都有可能访问各自的虚拟地址,但是映射之后的物理内存就不会是同一个地址。所以在多进程编程中,不要寄希望于通过地址来判断两个变量是否相同。所以,两个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。这也是fork为什么叫fork的原因至于那一个最先运行,可能与操作系统(调度算法)有关,而且这个问题在实际应用中并不重要,如果需要父子进程协同,可以通过原语的办法解决。


你可能感兴趣的:(c,linux,函数,操作系统,计算机)