关于创建 N 个子进程 和 fork 函数的理解
有如下 代码 创建 N个 子进程
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(void)
{
int i;
pid_t pid;
printf("xxx\n");
for(i = 0; i<5; i++){
pid = fork();
if(pid == -1){
perror("fork error;");
exit(1);
}else if(pid == 0){
break;
//只创建子进程,不调用fork 函数 .一旦创建出子进程,立马退出for 循环执行for循环后面的语句,直到return 0; 结束这一个子进程。
}else{
printf("father , i=%d,pid = %u\n",i,getpid()); 父进程
}}
sleep(i);
printf("===========pid = %u\n",pid);
if(i < 5){
printf("I am %d child , i=%d,pid = %u\n",i+1,i,getpid());
}else{ // i= 5 时 创建的是父进程
printf("I am father , i=%d,pid = %u\n",i,getpid());
} return 0;
}
运行结果
xxx
father , i=0,pid = 19388
father , i=1,pid = 19388
father , i=2,pid = 19388
father , i=3,pid = 19388
father , i=4,pid = 19388
===========pid = 0
I am 1 child , i=0,pid = 19389
===========pid = 0
I am 2 child , i=1,pid = 19390
===========pid = 0
I am 3 child , i=2,pid = 19391
===========pid = 0
I am 4 child , i=3,pid = 19392
===========pid = 0
I am 5 child , i=4,pid = 19393
===========pid = 19393
I am father , i=5,pid = 19388
可以看到 不仅 子进程 创建了 5个 , 父进程也有六次打印信息 (但父进程的个数只有 一个 ,因为 这六个 父进程的进程pid 相同)。
而且 我们隔离了 子进程使用 fork 函数(使用 break 语句 跳出循环 )。
我们要明白fork 函数 有两个返回值
先看 for 循环逻辑,如果是fork 函数 返回是 0 ,为子进程 ,就break .执行 for 循环之后的语句,return 0 ;结束
如果是fork 函数 返回 值 大于 0 ,为父 进程,i ++ ,又会执行 fork 函数 ,在i < 5,之前是不会跳出for循环的。
所以,后面可以使用 if( i< 5) 就是 子进程 跳出了循环。
而当 if (i >=5 ) 就是父进程 跳出循环,而且 并未执行 fork 语句,所以 i =5 就是一个干净的 父进程。.
如图 可见 当 n =6 (i=6)的时候 , 并未 调用fork 函数,只有一个 parent 进程。
这个过程中 parent 被打印 了六次,但全是一个 parent 进程(pid 相同),而子进程确是真创建了 五 个。 { 注意图上 是从 n =1 开始的 而代码里是 n=0 开始的,所以 n= 6 和 i=5 相同}
顺便一提,这六个进程 (父子进程) 如果 不使用 sleep 限制 ,他们是相等 地位 获得处理机的。所以 会 发生 抢占处理机
第二种 创建 多个子进程的方法相同
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
pid_t pid;
int i;
for (i = 0; i < 3; i++)
{
pid = fork();
/*
这个地方要判断pid是否为0是因为fork函数的实现原理,fork函数最后的return 0是子进程进行
的,所以进入这个判断的是子进程,而子进程返回的pid就是0,如果这个地方不加上该判断,子进
程也会进入该for循环来创造进程,子又生孙孙又生子,而我们只希望父进程来创建三个子进程,
所以加上了该判断
*/
if (pid == 0)
{
break;
}
}
首先父进程进入下面的三个判断,因为父进程pid大于0,所以会进入第一个判断,打印出父进程的
pid,然后我们用while循环一直sleep(1)来阻塞父进程,让子进程进入三个判断,因为子进程的pid
是0,所以会进入第二个判断,第一个子进程先进入判断,进入if(i == 0)用execl函数重载来实现功
能,后面执行同样的步骤,也是父进程先进入判断, 之后两个进程分别进入判断
if (pid > 0)
{
printf("parent pid %d\nsleeping..\n", getpid());
while (1)
{
sleep(1);//如果检测到父进程创建 ,就阻塞掉父进程执行
}
}
else if (pid == 0)
{
if (i == 0)
{
printf("child no.%d pid %d exec firefox..\n", i, getpid());
}
if (i == 1)
{
printf("child no.%d pid %d touch files..\n", i, getpid());
}
if (i == 2)
{
printf("child no.%d pid %d exec ls -l..\n", i, getpid());
}
}
return 0;
}