参见百度百科API说明:html
#include<unistd.h>app
#include<sys/types.h>函数
pid_t fork( void);spa
(pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中).net
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;不然,出错返回-13d
一个现有进程能够调用fork函数建立一个新进程。由fork建立的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的惟一区别是子进程中返回0值而父进程中返回子进程ID。code
子进程是父进程的副本,它将得到父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。htm
UNIX将复制父进程的地址空间内容给子进程,所以,子进程有了独立的地址空间。在不一样的UNIX (Like)系统下,咱们没法肯定fork以后是子进程先运行仍是父进程先运行,这依赖于系统的实现。因此在移植代码的时候咱们不该该对此做出任何的假设。blog
因为在复制时复制了父进程的堆栈段,因此两个进程都停留在fork函数中,等待返回。所以fork函数会返回两次,一次是在父进程中返回,另外一次是在子进程中返回,这两次的返回值是不同的。过程以下图进程
调用fork以后,数据、堆栈有两份,代码仍然为一份可是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。
fork函数的特色归纳起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。
fork的另外一个特性是全部由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增长。
vfork(创建一个新的进程)
相关函数wait,execve
头文件 #include<unistd.h>
定义函数pid_t vfork(void);
vfork()会产生一个新的子进程.可是vfork建立的子进程与父进程共享数据段,并且由vfork建立的
子进程将先于父进程运行.fork()的使用详见百度词条fork().
vfork()用法与fork()类似.可是也有区别,具体区别归结为如下3点:
1. fork():子进程拷贝父进程的数据段,代码段. vfork():子进程与父进程共享数据段.
2. fork():父子进程的执行次序不肯定.
vfork():保证子进程先运行,在调用exec或exit以前与父进程数据是共享的,在它调用exec
或exit以后父进程才可能被调度运行。
3. vfork()保证子进程先运行,在她调用exec或exit以后父进程才可能被调度运行。若是在
调用这两个函数以前子进程依赖于父进程的进一步动做,则会致使死锁。
4.当须要改变共享数据段中变量的值,则拷贝父进程。
我的理解: fork和vfork均可以用来建立子进程.fork建立子进程后,父子进程的数据段和堆栈段分离,会产生复制消耗资源.而在实际的应用中,有时是不须要的.好比子进程建立后就执行exec调用了.这样就产生了vfork,其产生的子进程和父进程共享数据段. 同时fork建立的子进程和父进程的运行的前后顺序是没有保证的,便可能父进程先运行,也可能子进程先运行.而vfork的特色是保证子进程先运行.只有子进程经过经过exec或者exit退出后,父进程才能运行.但这个特定也决定了,若是子进程依赖父进程的操做的话,就会产生死锁(即其须要父进程执行,而父进程必须在其完成后才能执行,互相等待)。 |
下面经过几个例子加以说明:
第一:子进程拷贝父进程的代码段的例子:
1: #include<sys/types.h>
2: #include<unistd.h>
3: #include<stdio.h>
4:
5: int main()
6: {
7: pid_t pid;
8: pid = fork();
9: if(pid<0)
10: printf("error in fork!\n");
11: else if(pid == 0)
12: printf("I am the child process,ID is %d\n",getpid());
13: else
14: printf("I am the parent process,ID is %d\n",getpid());
15: return 0;
16:
17: }
运行结果:
cnt=1
I am the child process,ID is 2164
cnt=1
I am the parent process,ID is 2163
为何两条语 都会打印呢?这是由于fork()函数用于从已存在的进程中建立一个新的进
程,新的进程称为子进程,而原进程称为父进程,fork ()的返回值有两个,子进程返回0,
父进程返回子进程的进程号,进程号都是非零的正整数,因此父进程返回的值必定大于零,
在pid=fork();语句以前只有父进程在运行,而在pid=fork();以后,父进程和新建立的子进程
都在运行,因此若是pid==0,那么确定是子进程,若pid !=0 (事实上确定大于0),那么是
父进程在运行。而咱们知道fork()函数子进程是拷贝父进程的代码段的,因此子进程中一样
有
if(pid<0)
printf("error in fork!");
else if(pid==0)
printf("I am the child process,ID is %d\n",getpid());
else
printf("I am the parent process,ID is %d\n",getpid());
}
这么一段代码,因此上面这段代码会被父进程和子进程各执行一次,最终因为子进程的pid= =0,
而打印出第一句话,父进程的pid>0,而打印出第二句话。因而获得了上面的运行结果。
再来看一个拷贝数据段的例子:
1: #include<sys/types.h>
2: #include<unistd.h>
3: #include<stdio.h>
4:
5: int main()
6: {
7: pid_t pid;
8: int cnt = 0;
9: pid = fork();
10: if(pid<0)
11: printf("error in fork!\n");
12: else if(pid == 0)
13: {
14: cnt++;
15: printf("cnt=%d\n",cnt);
16: printf("I am the child process,ID is %d\n",getpid());
17: }
18: else
19: {
20: cnt++;
21: printf("cnt=%d\n",cnt);
22: printf("I am the parent process,ID is %d\n",getpid());
23: }
24: return 0;
25: }
你们觉着打印出的值应该是多少呢?是否是2 呢?先来看下运行结果吧
为何不是2 呢?由于咱们一次强调fork ()函数子进程拷贝父进程的数据段代码段,因此
cnt++;
printf("cnt= %d\n",cnt);
return 0
将被父子进程各执行一次,可是子进程执行时使本身的数据段里面的(这个数据段是从父进
程那copy 过来的如出一辙)count+1,一样父进程执行时使本身的数据段里面的count+1,
他们互不影响,与是便出现了如上的结果。
那么再来看看vfork ()吧。若是将上面程序中的fork ()改为vfork(),运行结果是什么
样子的呢?
原本vfock()是共享数据段的,结果应该是2,为何不是预想的2 呢?先看一个知识点:
vfork 和fork 之间的另外一个区别是:vfork 保证子进程先运行,在她调用exec 或exit 之
后父进程才可能被调度运行。若是在调用这两个函数以前子进程依赖于父进程的进一步动
做,则会致使死锁。
这样上面程序中的fork ()改为vfork()后,vfork ()建立子进程并无调用exec 或exit,
因此最终将致使死锁。
怎么改呢?看下面程序:
1: #include<sys/types.h>
2: #include<unistd.h>
3: #include<stdio.h>
4:
5: int main()
6: {
7: pid_t pid;
8: int cnt = 0;
9: pid = vfork();
10: if(pid<0)
11: printf("error in fork!\n");
12: else if(pid == 0)
13: {
14: cnt++;
15: printf("cnt=%d\n",cnt);
16: printf("I am the child process,ID is %d\n",getpid());
17: _exit(0);
18: }
19: else
20: {
21: cnt++;
22: printf("cnt=%d\n",cnt);
23: printf("I am the parent process,ID is %d\n",getpid());
24: }
25: return 0;
26:
27: }
refer:http://baike.baidu.com/view/1952900.htm