进程的创建
提到进程创建,我们就需要来认识一下 fork()函数。
fork()从一个已经存在的进程中创建一个新的进程。新进程为子进程,而原进程为父进程。
如果fork()函数调用出错则会返回-1,否则子进程返回0,而父进程返回的是子进程的ID。
调用fork()函数以后,当控制转移到内核中的fork()代码以后,内核会进行以下几项工作:
分配新的内存块和内核数据结构给子进程
将父进程部分数据结构内容拷贝至子进程
添加子进程到系统进程列表当中
fork返回,开始调度器调用
当一个进程调用fork函数以后,就有两个二进制代码相同的进程。而且他们都运行到相同的地方。但每个进程都将可以开始他们自己的工作内容。
#include<stdio.h>
#include<unistd.h>//fork函数的头文件
int main()
{
printf("before:pid->%d\n",getpid());
pid_t id = fork();
if(id < 0)
{
perror("fork");
return;
}
printf("after:pid->%d,fork return %d\n",getpid(),id);
sleep(1);
return 0;
}
运行结果如下:
这里是进程26480先打印before消息,这是调用fork函数之前父进程独立执行的结果,
调用fork函数以后,父进程与子进程分别执行,但是执行的先后顺序有调度器决定。调用以后父进程打印after消息,子进程打印after消息。
这里还有另外一个vfork函数。也是用来创建子进程,但是vfork创建一个子进程,子进程与父进程共享地址空间,fork的子进程是具有独立地址空间的。另外,vfork保证子进程先运行,在它调用exec或(exit)之后父进程才可能被调度运行。
#include<stdio.h>
#include<unistd.h>
int main()
{
int num = 20
pid_t id = vfork();
if(id < 0)
{
perror("vfork");
return;
}
else if(id == 0)
{
sleep(1);
num = 2000;
printf("child num:%d\n",num);
exit(0);
}
else
{
printf("father num:%d\n",num);
}
return 0;
}
运行结果如下:
从运行结果可以看出,子进程将父进程的变量值也进行了修改,正是因为子进程在父进程的地址空间中运行,所以才会有这样的结果。