电子常识
在Linux中fork函数是非常重要的函数,它的作用是从已经存在的进程中创建一个子进程,而原进程称为父进程。
调用fork(),当控制转移到内核中的fork代码后,内核开始做:
1.分配新的内存块和内核数据结构给子进程。
2.将父进程部分数据结构内容拷贝至子进程。
3.将子进程添加到系统进程列表。
4.fork返回开始调度器,调度。
来段代码:
1 #include《stdio.h》
2 #include《unistd.h》
3 #include《stdlib.h》
4 int main()
5 {
6 pid_t pid;
7 printf(“before :pid is %d ”,getpid());
8 if((pid=fork())==-1)
9 perror(“fork()”),exit(1);
10 printf(“After:pid=%d,fork return %d ”,getpid(),pid);
11 sleep(1);
12
13 return 0;
14 }
15 123456789101112131415
这个简单的例子有一些微妙的方面:
•调用一次,返回两次
fork函数被父进程调用一次,但是却返回两次;一次是返回到父进程,一次是返回到新创建的子进程。
•并发执行
子进程和父进程是并发运行的独立进程。内核能够以任意的方式交替执行他们的逻辑控制流中的指令。在我们的系统上运行这个程序时,父进程先运行它的printf语句,然后是子进程。
•相同但是独立的地址空间
因为父进程和子进程是独立的进程,他们都有自己私有的地址空间,当父进程或者子进程单独改变时,不会影响到彼此,类似于c++的写实拷贝的形式自建一个副本。
•fork的返回值
1.fork的子进程返回为0;
2.父进程返回的是子进程的pid。
•fork的常规用法
1.一个父进程希望复制自己,使得子进程同时执行不同的代码段,例如:父进程等待客户端请求,生成一个子进程来等待请求处理。
2.一个进程要执行一个不同的程序。
•fokr调用失败的原因
1.系统中有太多进程
2.实际用户的进程数超过限制
在linux下,C语言创建进程用fork函数,接下来我们通过代码来一步步了解fork函数的各个知识点。
1、依赖的头文件
1#include 《unistd.h》
2、fork的原理和概念
fork子进程就是从父进程拷贝一个新的进程出来,子进程和父进程的进程ID不同,但用户数据一样。
在C语言中,创建一个子进程代码如下:
pid_t pid; //pid_t 从底层来看,实际上是int类型。
pid = fork();
3、父进程和子进程
执行fork函数后有2种返回值:对于父进程,返回的是子进程的PID(即返回一个大于0的数字);对于子进程,则返回0,所以我们可以通过pid这个返回值来判断当前进程是父进程还是子进程。如下代码所示:
if(pid 》 0)
{
printf(“im parent process, pid: %d ”, getpid());
}
else if(pid == 0)
{
printf(“im child process, pid: %d, parent pid: %d ”, getpid(), getppid());
}
else
{
printf(“fork failed ”);
}
温馨提示:
getpid() -获取当前进程的pid
getppid() -获取当前进程的父进程的pid
4、完整例子&子进程代码执行位置
了解这些之后,我们来看一个创建子进程的完整代码示例:
#include 《stdio.h》
#include 《unistd.h》
int main(int argc, char *argv[])
{
printf(“========== before fork ============= ”);
pid_t pid;
pid = fork();
printf(“========== after fork ============= ”);
if(pid 》 0)
{
printf(“im parent process, pid: %d ”, getpid());
}
else if(pid == 0)
{
printf(“im child process, pid: %d, parent pid: %d ”, getpid(), getppid());
}
else
{
printf(“fork failed ”);
}
printf(“========== process end ============= ”);
sleep(1);
return 0;
}
运行结果如下图:
从上图可以看出,程序只输出了1个“before fork”,但输出了2个“after fork”,所以我们可以得出:子进程的代码执行是从fork()位置之后开始的。事实也确实是如此。
5、循环创建子进程
有时候,我们需要创建多个子进程,可以通过for循环来实现,代码如下:
#include 《stdio.h》
#include 《unistd.h》
int main(int argc, char *argv[])
{
int i = 0;
pid_t pid;
for(i = 0; i 《 3; i++)
{
pid = fork();
}
if (pid == 0)
{
printf(“im child process, pid: %d, parent pid: %d ”, getpid(), getppid());
}
else
{
printf(“im parent process, pid: %d ”, getpid());
}
sleep(1);
return 0;
}
运行结果如下图:
咦,我们不是循环创建3个子进程吗,怎么输出了这么多次parent process和child process呢?
这是因为子进程也创建了子进程,大家可以观察一下图中的pid。数了一下,共输出了8次,刚好是2的3次方。
我画了一个fork步骤图,便于大家更好的理解,如下:
如上图所示,子进程在第2轮、3轮,也会相当于父进程一样继续fork子进程,所以for循环3次后,刚好得到共8个进程。
那如果我们就想通过循环3次,得到3个子进程,要怎么办呢?
思路:不让子进程fork出新的子进程。
代码片段如下:
for(i = 0; i 《 3; i++)
{
pid = fork();
if (pid == 0)
{
break;
}
}
运行结果:
至此,fork函数创建子进程介绍完毕。
责任编辑:YYX
全部0条评论
快来发表一下你的评论吧 !