fork和vfork那些事vfork: #include <stdio.h> #include <sched.h> #include <unistd.h> int data = 10; int child_process(){ printf("Child process %d, data1 %d\n",getpid(),data); data = 20; printf("Child process %d, data2 %d\n",getpid(),data); _exit(0); } int main(int argc, char* argv[]){ if(vfork()==0) { child_process(); }else{ sleep(1); printf("Parent process %d, data3 %d\n",getpid(), data); } } 你知道上述data1、data2和data3分别是多少吗?先自己思考下,后文一起解密。 fork: #include <sched.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int data = 10; int child_process(){ printf("Child process %d, data4 %d\n",getpid(),data); data = 20; printf("Child process %d, data5 %d\n",getpid(),data); _exit(0); } int main(int argc, char* argv[]){ int pid; pid = fork(); if(pid==0) { child_process(); }else{ sleep(1); printf("Parent process %d, data6 %d\n",getpid(), data); exit(0); } } 上述代码改动了一个地方,就是把vfork换成了fork,你知道data4、data5和data6的结果吗?我们先来分析下vfork和fork的区别,然后再公布答案。 先说fork吧。fork创建出子进程后,子进程复制了父进程的资源,诸如文件系统,打开的文件,信号等,但是内存空间却是用了写时拷贝机制(Copy On Write),简单介绍下写时拷贝机制,就是子进程拷贝父进程的页表,并将父进程中具有写权限的物理页对应的页表项置为只读,也就是说,此时父子进程具有相同的页表,虚拟地址对应的物理地址也一样,只是物理地址都是只读的,当子进程或父进程其中的一个写物理内存时,由于是只读的,所以会发生pagefault,此时才给执行写操作的进程分配物理页,并将新分配的物理页连接到执行写操作的进程的页表中,最后把旧物理页对应的在没执行写操作的进程的页表项改为可写。这样一来,父子进程相同的虚拟地址就对应了不同的物理地址。看完上述的分析,那么data4、data5和data6分别是10、20和10.你答对了吗? 再说vfork。vfork创建出子进程后,子进程复制了父进程的文件系统、打开的文件、信号等资源,但是内存空间却是与父进程共享的,且父进程会阻塞,直到子进程执行exit(0)或执行exec。由于共享内存,所以data1、data2和data3的值就是10、20和20. 最后在说一点,我们从分析中也可看出,fork是依赖Copy On Write机制的,而写时拷贝机制依赖MMU,所以在没有MMU的CPU上,就没有fork,但是可以有vfork。 |
|