Linux--进程的创建
一.进程创建有三种方式(这里主讲fork及vfork)
1.fork
2.vfork
3. clone
二.fork函数
1.fork用于创建一个新进程;
2.fork函数没有参数,且有两个返回值,如果fork失败返回-1,如果成功,父进程返回子进程pid,子进程返回0; (pid_t fork( ));
3.当进程调用fork时,内核会做如下的事情:
-
分配新的控制块和内核数据结构给子进程;
-
将父进程的部分数据和代码拷贝至子进程,且采用写时拷贝;
-
然后将子进程添加到系统进程列表中;
-
fork返回之后,开始调度器调度。
4.fork之前只有父进程在执行,fork之后,父子进程同时执行fork之后的代码。
例如:
#include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 printf("Before : pid=%d\n",getpid());
7 pid_t id = fork();
8
9 if(id<0)
10 {
11 perror("fork()");
12 }
13
14 printf("After: pid=%d, fork return %d\n",getpid(),id);
15 sleep(1);
16 return 0;
17 }
运行结果如下:(可以发现在执行fork之前,当前只有一个进程,也就只有一个进程输出“Before...”,fork之后父进程创建了一个子进程,父子进程同时执行fork之后的代码
5.fork调用失败的原因
1.内存不够;
2.创建进程数超过限制
三.vfork的使用及两种进程创建方式的区别
1.vfork创建的进程,保证子进程先执行,当子进程调用exec之后父进程才执行;而fork创建的子进程和父进程谁先执行并不确定,是由操作系统的调度器决定的。
2.vfork创建的一个子进程,父子进程共享同一块地址空间,而fork创建的子进程和父进程具有独立的地址空间;
3.vfork的使用程序(该vfork会让子进程先执行,然后让子进程睡3秒之后再退出,所以程序会在子进程先输出,经过3秒后才让父进程输出)
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid = vfork();
if(pid<0)
{
perror("vfork()");
}
else if(pid>0)
{
//parent
printf("parent pid=%d\n",getpid());
}
else
{
//child
printf("child pid=%d\n",getpid());
sleep(3);
exit(1);
}
return 0;
}
运行结果:
4.如果让父进程等待10秒后再执行程序,则当子进程执行完自己的程序后会变成僵尸状态,直到10秒后,子进程才被彻底销毁。程序如下:
int main()
{
pid_t pid = vfork();
if(pid <0)
{
perror("vfork()");
}
else if(pid == 0)
{
//child
printf("child pid=%d\n",getpid());
exit(1);
}
else
{
//parent
sleep(10);
printf("parent pid=%d\n",getpid());
}
return 0;
}
结果如下:
5.如何证明vfork创建的子进程与父进程共用同一块地址空间
可以定义一个全局变量,通过子进程修改这个全局变量的值观察两个进程输出这个变量的值是否相同
(1)用fork创建的子进程满足上面的要求
#include<unistd.h>
int g_value = 10;
int main()
{
pid_t pid = fork();
if(pid<0)
{
perror("fork()");
}
else if(pid == 0)
{
//child
sleep(5);
g_value = 200;
printf("child g_value=%d\n",g_value);
}
else
{
//parent
printf("parent g_value=%d\n",g_value);
}
return0;
}
运行结果:(可以看到父子进程输出的值不同)
(2)用vfork创建的子进程满足上面的要求
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int g_value = 100;
int main()
{
pid_t pid = vfork();
if(pid<0)
{
perror("vfork()");
}
else if(pid>0)
{
//parent
printf("parent pid=%d g_value=%d\n",getpid(),g_value);
}
else
{
//child
sleep(5);
g_value = 200;
printf("child pid=%d g_value=%d\n",getpid(),g_value);
exit(1);
}
return 0;
}
运行结果:(可以看到子进程改变 变量的值,父进程里面那个变量的值也会被改,则说明父子进程共用同一块地址空间)
(3)当一个父进程用vfork同时创建多个子进程时,现象如下:
pid_t pid1 = vfork();
pid_t pid2=vfork();
if(pid1<0)
{
perror("vfork()\n");
}
else if(pid1 == 0)
{
//child
g_value = 200;
printf("child1 g_value=%d\n",g_value);
exit(1);
}
else
{
//parent
printf("parent1 g_value=%d\n",g_value);
}
if(pid2 < 0)
{
perror("vfork()");
}
else if(pid2 == 0)
{
printf("child2 g_value=%d\n",g_value);
exit(1);
}
运行结果: