vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。vfork与fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会存访该地址空间。不过在子进程调用exec或exit之前,它在父进程的空间中运行。这种工作方式在某些UNIX的页式虚存实现中提高了效率(与上节中提及的,在fork之后跟随exec,并采用在写时复制技术相类似)。
vfork和fork之间的另一个区别是:vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)
/**** vfork ******/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include #include #include int main(void) { FILE* pfile = fopen("/home/jack/AAA.txt", "w"); pid_t pid; char buf[256] = { 0 }; if ((pid = vfork()) < 0) { printf("fork error!"); } else if (pid == 0) //child { sleep(1); //不管sleep多久都先执行 strcpy(buf, "1234656789"); fwrite(buf, 9, 1, pfile); printf("child %d", getpid()); strcpy(buf, "ABCDEFGHI"); exit(0); } else { fwrite(buf, 9, 1, pfile); printf("parent: %d\n", getpid()); fclose(pfile); } printf("after child changed buf---> %s \n",buf); //子进程使用的是父进程的空间,so.. return 0; }
关于fork()
1)子进程获得父进程数据空间、堆和栈的复制品。注意,这是子进程所拥有的拷贝。父、子进程并不共享这些存储空间部分。如果正文段是只读的,则父、子进程共享正文段。
2)一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的。
3)在重新定向父进程的标准输出时,子进程的标准输出也被重新定向。实际上,fork的一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程每个相同的打开描述符共享一个文件表项。 共享文件的话,会使用同一个文件位移量。如下:
/*** 子进程与父进程 共享同一个文件 ,它们使用了同一个文件位移量 ***/ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { FILE* pfile = fopen("/home/jack/AAA.txt", "w"); pid_t pid; char buf[256] = { 0 }; if ((pid = fork()) < 0) { printf("fork error!"); } else if (pid == 0) //child { sleep(1); //让父进程先执行(但不一定能保证父进程先执行) printf("child file pos: %d\n",ftell(pfile)); //这里打印的结果是9 说明偏移 更新了。 strcpy(buf, "1234656789"); fwrite(buf, 9, 1, pfile); printf("child %d", getpid()); exit(0); } else { strcpy(buf, "ABCDEFGHI"); fwrite(buf, 9, 1, pfile); printf("parent: %d\n", getpid()); fclose(pfile); } printf("parent buf---> %s \n",buf); //两进程的内存空间是相互独立的 return 0; } /************** AAA.txt的内容是:ABCDEFGHI123465678 ***************/