0.序
1.基础内容介绍
1)进程的组成:
2)fork函数调用后,系统所做工作:
2.函数详细介绍
1)函数原型
2)作用
3)描述
3.总结:
|
fork函数是Linux中创建进程的函数,也是唯一一个创建进程的函数。因此学好fork函数时基础中的基础。0.序
1.基础内容介绍
1)进程的概述:
进程简单的说就是一个程序一次执行的过程,它是一个动态的概念。按照教科书上的定义,进程是程序执行的实例,是linux的基本调度单位。
对于程序员来说,最重要的就是要区分进程和程序的区别,程序是指一段完成功能的代码,或者说是一个工具,它是一个静态的概念,而进程,它是动态的,比如,linux的vi编辑器,它就是一段在linux下用于文本编辑的工具,那么它是一个程序,而我们在linux终端中,可以分别开启两个vi编辑器的进程。一旦提到进程,我们的脑子里就应该产生——程序从代码的第一句动态的执行到最后一句这样的一个思路。
一个进程由如下元素组成:1.> 进程的当前上下文,即进程的当前执行状态;2.> 进程的当前执行目录3.> 进程访问的文件和目录4.> 进程的访问权限,比如它的文件模式和所有权
5.> 内存和其他分配给进程的系统资源
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
2)fork函数调用后,系统所做工作:
一个进程调用fork()函数后,
(1)系统先给新的进程分配资源,例如存储数据和代码的空间。
(2)然后把原来的进程的所有值都复制到新的新进程中,只有少数值(这部分少数值在man fork中有详细说明)与原来的进程的值不同。相当于克隆了一个自己。
2.函数详细介绍
1)函数原型
SYNOPSIS #include <unistd.h> pid_t fork(void); |
2)作用
创建一个子进程。是进程不是线程。
3)描述
( 1)通过复制调用进程(即父进程)来创建一个子进程。
所谓复制:子进程会与父进程共享代码空间,但是其数据空间是相互独立的。子进程的数据空间是从父进程完成拷贝下来的,刚创建完子进程时里面的取值都与父进程一样,但是由于其数据空间是相互独立的,因此数据空间中的数据会随着子进程的进行,而发生改变,从而与父进程不再一样。
fork函数的作用是在其进程中创建一个新的进程,这个新的进程不会取代原来的进程,而是以当前进程的一个子进程而存在的。这个子进程会有一个新的进程标识符pid。并且这个子进程会继承父进程的一切!
什么是叫继承父进程的一切呢?就是克隆父进程的所有,包括父进程的
代码,
父进程正在执行的状态,
父进程的工作目录,
父进程的所有资源等等,一切的一切,fork系统调用会全部的复制下来。
举例:
/*可以用于说明父子进程间数据空间是相互独立的*/ #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int glob = 6; char buf[] = "a write to stdout/n"; int main() { int var; pid_t pid; var = 88; fprintf(stderr, "%s", buf); printf("before fork\n"); if(( pid = fork() ) < 0 ) { fprintf(stderr, "fork error\n"); } else if(pid == 0) { glob++; var++; printf("child process\n"); printf("pid = %d getpid = %d, father pid = %d, glob = %d, var = %d\n",pid, getpid(), getppid(), glob, var); exit(0); } else { var += 20; glob += 20; printf("begin into father process\n"); sleep(2); printf("father process\n"); printf("pid = %d, father pid = %d, glob = %d, var = %d\n", getpid(), getppid(), glob, var); } return 0; } |
运行结果
a write to stdout/nbefore fork begin into father process child process pid = 0 getpid = 4039, father pid = 4038, glob = 7, var = 89 father process pid = 4038, father pid = 3317, glob = 26, var = 108 |
(2)创建新进程成功后,系统中出现两个基本完全相同的进程,
这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
(3)当创建完毕后,可以想象,两个进程一直同时进行,而且步调一致,在fork之后,他们分别做不同的工作,也就是分岔了,这就是为什么叫fork的原因. fork执行完毕后,出现两个进程。
根据1)中所述,父子进程共享代码空间,因此二者代码相同。又根据1)中所述,二者数据空间相互独立,根据fork在父进程与子进程的返回值的不同,父子进程将会执行不同的代码段,从而实现不同的功能。

4)特别重要的一点:fork是把进程当前的情况拷贝一份。切记是当前的情况拷贝一份,而不是代码中原始数据的拷贝。这一点通过下面的代码最能体现。
#include <unistd.h> #include <stdio.h> int main(void) { int i=0; printf("i son/pa ppid pid fpid\n"); //ppid指当前进程的父进程pid //pid指当前进程的pid, //fpid指fork返回给当前进程的值 for(i=0;i<2;i++){ pid_t fpid=fork(); if(fpid==0) printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid); else printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid); } return 0; } |
其运行结果
i son/pa ppid pid fpid 0 parent 3317 4096 4097 1 parent 3317 4096 4098 1 child 1 4098 0 0 child 1 4097 0 1 parent 1 4097 4099 1 child 1 4099 0 |
之所以运行结果的顺序与http://blog.youkuaiyun.com/jason314/article/details/5640969 文中不同,我想就是因为
这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
3.总结:
fork()函数通过系统调用创建了一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事(因为共享代码空间),但是由于fork函数的返回值的不同,会产生不同的功能(fork返回值不同,会去执行不同代码段,又因为数据空间是相互独立,故数据互不影响)。
重点记住两点:1)共享程序空间,数据空间相互独立
2)父子进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
http://coolshell.cn/articles/7965.html 一个fork的面试题