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
***************/