apue学习之fork函数基础
随着一句fork,一个新进程呱呱落地,但它这时只是老进程的一个克隆。
然后随着exec,新进程脱胎换骨,离家独立,开始了为人民服务的职业生涯。
人有生老病死,进程也一样,它可以是自然死亡,即运行到main函数的最后一个”}”,从容地离我们而去;也可以是自杀,自杀有2种方式,一种 是调用 exit函数,一种是在main函数内使用return,无论哪一种方式,它都可以留下遗书,放在返回值里保留下来;它还甚至能可被谋杀,被其它进程通过 另外一些方式结束他的生命。
进程死掉以后,会留下一具僵尸,wait和waitpid充当了殓尸工,把僵尸推去火化,使其最终归于无形。
————————————————padden_zhang(主页)
1 函数接口
#include<unistd.h>
pid_t fork(void);
返回值:子进程返回0,父进程返回子进程ID;若出错,返回-1。
fork()创建的新进程被称为子进程,fork()调用一次但是返回2次。
2 示例程序
// File Name: fork_test.c
// Author: AlexanderGan
// Created Time: Fri 29 May 2020 07:51:17 PM CST
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int num = 0;
int main(int argc, char* argv[]){
printf("begin!\n ");
pid_t pid = fork();
if(pid < 0)
{
perror("fork error");
exit(1);
}
if(pid == 0)
{
//child process
num = 11;
printf("new num = %d \n",num);
printf("I am a child, pid = %d ,ppid = %d\n",getpid(),getppid());
}
else if (pid > 0)
{
//parent process
sleep(1);
printf("new num = %d \n",num);
printf("I am a parent,child pid=%d,self = %d,ppid = %d\n",pid,getpid(),getppid());
printf("END...\n");
return 0 ;
}
运行结果
3 原理解析
3.1 fork()基本原理
fork的实现分为以下两步
- 复制进程资源
- 执行该进程
复制进程的资源包括以下几步
3. 进程pcb
4. 程序体,即代码段数据段等
5. 用户栈
6. 内核栈
7. 虚拟内存池
8. 页表
3.2 fork()注意事项
1) fork()之后子进程获得获得父进程数据空间、堆和栈的副本,注意是复制了一份,而不是共享。(通常采用写时复制,也就是开始的时候共享这些资源,并将访问权限改为只读,只在父子进程任意一个要修改这些资源时,才复制。)
2)父子进程共享正文段。
刚fork()完之后父子进程:
相同点:
全局变量、.data、.text、栈、堆、环境变量,用户id,宿主目录、进程工作目录、信号处理方式。
不同点:
进程id、fork()返回值、进程运行时间等