UNIX操作系统的底层接口:系统调用是用户程序与系统内核的接口。,创建一个新进程的唯一方法是由一个已经存在的进程通过调用fork()、vfork()、和clone()函数来实现。已存在创建者进程叫做父进程,被创建进程叫做子进程。
首先学习的是fork()函数,用该函数创建进程时,语句调用序列如下。
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void)
返回:调用正确时,给父进程返回的是被创建子进程的标识,给子进程返回的是0;创建失败时,返回父进程的是-1.
fork()函数是一个单调用双返回的函数。下面是一个fork()系统调用的使用例子
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int glob = 3;
int main()
{
pid_t pid;
int loc = 3;
printf("before fork(): glob = %d, loc = %d.\n",glob,loc);
if((pid = fork()) < 0)
{
printf("fork() error.\n");
exit(0);
}
else if(pid == 0)
{
glob++;
loc--;
printf("child process changes glob and loc;\n");
}
else
printf("parent process doesn't change the glob and loc;\n");
printf("glob = %d, loc = %d\n",glob,loc);
exit(0);
return 0;
}
这只是其中一种结果。是因为由于上述程序运行时产生两个进程,由main()函数产生一个父进程以及程序执行中通过fork()产生的一个子进程。当执行到fork()后形成两个并发进程。根据系统调用情况,可能产生两种结果。
PS:fork()函数,子进程拷贝父进程的代码段、数据段,但是父子进程不共享数据段,但是使用Vfork()函数后,父子进程共享数据段。下面来看一下Vfork()函数
用Vfork()函数创建进程时,语句调用序列如下
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void)
返回值:正确返回时与fork()返回值一样,返回子进程标识,否则返回-1.用vfork()函数创建进程时,通常用exec()函数紧跟其后,以便为新创建进程指派另一个可执行程序。用vfork()创建的新进程并不完全复制父进程的数据区。vfork()调用后,子进程先运行,父进程挂起,直到子进程调用exec()或exit()之后,父子进程的执行顺序才不会有限制。否则,如果子进程在调用exec()或exit()之前,父进程被激活,就会造成死锁。
下面给出一个vfork()系统调用的例程
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int glob = 3;
int main()
{
pid_t pid;
int loc = 3;
if((pid = vfork()) < 0)
{
printf("vfork() error\n");
exit(0);
}
else if(pid == 0)
{
glob++;
loc--;
printf("child process changes the glob and loc\n");
exit(0);
}
else
printf("parent process doesn't change the glob and loc\n");
printf("glob = %d,loc = %d\n",glob,loc);
exit(0);
return 0;
}
这个程序只会产生一个结果,如下图所示
PS;Vfork()函数中父子进程共享数据段。
Vfork()创建进程成功后,父进程挂起,子进程先运行,在父进程的数据区中修改了glob和loc的值,并输出一句话,然后调用exit(0),子进程退出。由于父子进程共享地址空间,父进程继续运行,执行两条输出语句。由此看出glob和loc确实被子进程修改了。这就是vfork()和fork()的区别。