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 )。

举个样例:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
	int pid;
	pid=fork();
	printf("Hello\n");
	if(pid==0)
		printf("I'm child process.\n");
	else
		printf("I'm parent process.\n");
	return 0;
}

运行结果为:

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

#include<unistd.h>
#include<stdio.h>
int a=5;
int main()
{
   int b=6,pid;
   pid =fork();
   if(pid<0)
   {
      printf("Error\n");
   }
   else if(pid==0)
   {
      a++;
      b++;
      printf("Child process:%d\n",getpid());
      printf("%d %d %d\n",getpid(),a,b);
   }
   else
   {
      printf("Parent process:%d\n",getpid());
      printf("%d %d %d\n",getpid(),a,b);
   }
}

运行结果:

由此看出,子进程的值发生了改变。能够说明。它们并非共享的。

再来看下变量的地址:

#include<unistd.h>
#include<stdio.h>
int a=5;
int main()
{
   int b=6,pid;
   pid =fork();
   if(pid<0)
   {
      printf("Error\n");
   }
   else if(pid==0)
   {
      a++;
      b++;
      printf("Child process:%d\n",getpid());
      printf("%d %d %d %p %p\n",getpid(),a,b,&a,&b);
   }
   else
   {
      printf("Parent process:%d\n",getpid());
      printf("%d %d %d %p %p\n",getpid(),a,b,&a,&b);
   }
}

运行结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" >

由结果能够看出,变量地址是一样的!

!内容却不一样,由于打印的变量的地址都是逻辑空间, 对于父子进程。它们的逻辑空间一样,都是虚拟地址,可是物理空间还是不同的。每一个进程都有独立的4G的虚拟地址空间,映射到不同的物理空间。比方我如今同一时候执行两个进程,他们都有可能訪问各自的虚拟地址,可是映射之后的物理内存就不会是同一个地址。

所以在多进程编程中。不要寄希望于通过地址来推断两个变量是否同样。

所以,两个进程一直同一时候执行,并且步调一致,在fork之后,他们分别作不同的工作。也就是分岔了。这也是fork为什么叫fork的原因至于那一个最先执行。可能与操作系统(调度算法)有关,并且这个问题在实际应用中并不重要。假设须要父子进程协同,能够通过原语的办法解决。

最后看下父子进程的关系。看到网上有人说:

他们的关系是管理和被管理的关系,当父进程终止时。子进程也随之而终止。但子进程终止。父进程并不一定终止。比方httpdserver执行时,我们能够杀掉其 子进程,父进程并不会由于子进程的终止而终止。在Linux进程管理中,当我们发现占用资源过多,或无法控制的进程时。应该杀死它,以保护系统的稳定安全执行。

我们能够通过程序来验证一下是否正确看看:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
   int pid,v=1;
   pid=fork();
   if(pid==0)
   {
      printf("Child Process:pid=%d,ppid=%d,v=%d\n",getpid(),getppid(),v++);
      sleep(1);
      printf("Child Process:pid=%d,ppid=%d,v=%d\n",getpid(),getppid(),v++);
      exit(0);
   }
   else
   {
      printf("Parent Process:pid=%d,ppid=%d,v=%d\n",getpid(),getppid(),v++);
}

运行结果:

能够看出父进程首先退出,退出前child的PPID为6707。退出后子进程的PPID变为了1613.通过ps
命令查看到1613为init进程,说明父进程退出后的子进程由 init进程领养。而该子进程是不会退出的。

时间: 2024-10-27 13:31:42

Linux(1):fork函数的相关文章

linux中fork()函数详解[zz]

转载自:http://www.cnblogs.com/york-hust/archive/2012/11/23/2784534.html 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有

深入理解Linux的fork函数

一.问题引入 工作期间,某系统设计师抛出如下一个问题,下面的代码,输出几个"-"?: /****************************************************************************** Copyright by Thomas Hu, All rights reserved! Filename : fork01.c Author : Thomas Hu Date : 2012-8-5 Version : 1.0 Descript

linux的fork函数

   fork函数  头文件:#include<unistd.h> 函数原型:pid_t fork( void);(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中) 返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID:否则,出错返回-1  函数说明:一个现有进程可以调用fork函数创建一个新进程.由fork创建的新进程被称为子进程(child process).fork函数被调用一次但返回两次.两次返回的唯一区别

linux中fork函数的一个小思考

1.fork函数 头文件: #include<unistd.h> 函数原型: pid_t fork( void);(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中) 返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID:否则,出错返回-1 函数说明: 一个现有进程可以调用fork函数创建一个新进程.由fork创建的新进程被称为子进程(child process).fork函数被调用一次但返回两次.两次返回的唯一区别

Linux 中 fork() 函数详解

需要的头文件: #include <sys/types.h> #include <unistd.h> pid_t fork(void) 功能: 用于从一个已存在的进程中创建一个新进程,新进程称为子进程,原进程称为父进程. 参数: 无 返回值: 成功:子进程中返回 0,父进程中返回子进程 ID.pid_t,为无符号整型. 失败:返回 -1. 失败的两个主要原因是: 1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN. 2)系统内存不足,这时 err

Linux中fork函数详解

一.fork基础知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. fork()函数得到的子进程,继承父进程的所有系统资源,包括,代码段.数据区.常量区等

Linux中fork()函数详解

参考地址 1.对fork函数的认识: 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程, 也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都 复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. 需要注意的一点:就是调用fork函数之后,一定是两个进程同时执行的

linux之fork()函数详解

一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程, 也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都 复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. 我们来看一个例子: [cpp] view plaincopy /* *  fork

关于Linux下 fork() 函数的总结

看这一段代码,我想了一会儿,然后实验了一下午. #include <unistd.h> #include <stdio.h> int main() { pid_t pid; pid=fork(); if(pid==0){ while(1){ sleep(1); printf("haha\n"); } } if(pid>0) { while(1){ sleep(1); printf("hehe\n"); } } } 代码显而易懂,我开始想