fork函数用来创建子进程。
/* Clone the calling process, creating an exact copy.
Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
extern __pid_t fork (void) __THROWNL;
上图是Linux C库里面的unistd.h 中fork 函数的原型和相关注释。用我比较垃圾的英文水平进行一下翻译:将调用此函数的进程进行克隆,创建一个新的副本。返回-1表示error,0表示进入到子进程(new process),一个正整数表示返回子进程的pid给父进程(old process)。
fork函数早期是把父进程的所有存储空间全部复制给子进程,不过如今都使用写时拷贝,就是只在进程使用到的时候才拷贝某些需要的内容。如果父进程中有某些变量,在子进程中修改了,父进程中的值是不会变的。
使用场景:常常用于服务器(比如sokect)中服务器(server)接入客户端(client),主进程创建子进程给新的客户端运行接下来的程序,然后主进程继续检测是否有新的客户端接入。
demo.c:
#include
#include
#include
int main()
{
pid_t pid1;
pid_t pid2;
pid1 = getpid();
printf("原进程:%d\n", pid1);
pid2 = fork();
if(pid2 == -1)
{
printf("Fork error.\n");
}
else if (pid2 == 0)
{
printf("-----------------------------\n");
printf("这是子进程打印。\n");
printf("子进程:%d\n",getpid());
printf("fork函数返回:%d\n",pid2);
printf("-----------------------------\n");
}
else
{
printf("-----------------------------\n");
printf("这是父进程打印。\n");
printf("父进程:%d\n",getpid());
printf("fork函数返回:%d\n",pid2);
printf("-----------------------------\n");
}
return 0;
}
上面的demo可以看到fork函数的返回逻辑,创造一个新进程,在原进程中返回新进程的pid,在新进程中返回0。
再来介绍一下vfork函数,和fork函数比较相似:
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
extern __pid_t vfork (void) __THROW;
浅翻译一下:克隆调用该函数的进程,但是不复制整个地址区间。调用函数的进程会被暂停直到新进程退出或者被调用的execve函数替换。返回-1表示失败,0表示进入新的进程,一个pid_t的整数表示从新进程退出回到原进程,这个整数就是被开辟的新进程。
看完这个定义我就有了一个疑惑:既然复制地址区间,意思应该就是在父进程的内存空间上进行操作,那么子进程会改变父进程的变量等数据呢?写个代码验证一哈。
demo3.c
#include
#include
#include
int main()
{
int num = 0;
pid_t pid1;
pid_t pid2;
printf("The original process: %d\n", pid1);
pid2 = vfork();
if(pid2 = -1)
{
printf("vfork error.\n");
}
else if (pid2 = 0)
{
printf("------------------------------\n");
printf("This is child process: %d\n",getpid());
printf("vfork return: %d\n", pid2);
num++;
printf("num in child process: %d\n", num);
printf("------------------------------\n");
}
else
{
printf("------------------------------\n");
printf("This is parent process: %d\n",getpid());
printf("vfork return: %s\n", pid2);
num++;
printf("num in parent process: %d\n", num);
printf("------------------------------\n");
}
return 0;
}
验证如下:会改变父进程中的数值。
但是发现运行到后面段错误了,可能是子进程的返回不对,我再试试
修改方法就是在子进程中加上exit()函数就可以了。
21 printf("------------------------------\n");
22 printf("This is child process: %d\n",getpid());
23 printf("vfork return: %d\n", pid2);
24 num++;
25 printf("num in child process: %d\n", num);
26 printf("------------------------------\n");
27 exit(pid2);
可以继续验证子进程总是在父进程前运行,只要加上while循环验证就行了。