🌟hello,各位读者大大们你们好呀🌟
🍭🍭系列专栏:【Linux初阶】
✒️✒️本篇内容:fork进程创建,理解fork返回值和常规用法,进程终止(退出码、退出场景、退出方法、exit),进程等待(wait、waitpid),阻塞等待和非阻塞等待
🚢🚢作者简介:本科在读,计算机海洋的新进船长一枚,请多多指教( •̀֊•́ ) ̖́-
目录
(2)如何理解 fork返回后,给父进程返回子进程的 pid,给子进程返回 0?
(3)如何理解同一个 id值,会返回两个不同的值,让 if 和 else if 同时执行
一、进程创建
1.fork函数初识
在linux中fork函数是非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。
#include <unistd.h>
pid_t fork(void);
返回值:子进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核做:
- 分配新的内存块和内核数据结构给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表当中
- fork返回,开始调度器调度
如下图所示,调用fork后,将生成一个新的进程
代码示例如下
int main(void)
{
pid_t pid;
printf("Before: pid is %d\n", getpid());
if ((pid = fork()) == -1)perror("fork()"), exit(1);
printf("After:pid is %d, fork return %d\n", getpid(), pid);
sleep(1);
return 0;
}
运行结果:
[root@localhost linux]# . / a.out
Before : pid is 43676
After : pid is 43676, fork return 43677
After : pid is 43677, fork return 0
这里看到了三行运行结果,一行before,两行after。进程43676先打印before消息,然后它又打印after。另一个after消息是43677打印的。注意到进程43677没有打印before,为什么呢?如下图所示
我们可以看到上述代码中并没有对父子进程进行条件限制,那么在程序运行起来时,在 fork之后,会先执行父进程还是子进程呢?实际上,fork之后,谁先执行完全由调度器决定。
2.fork返回值
(1)如何理解 fork函数有两个返回值
首先,我们必须要知道 fork函数是操作系统为我们提供的,也就是说,fork操作是在操作系统内实现的。
接下来,我们一起来看下 fork函数内部的结构,然后思考一个问题:在代码在 return之前,内部的核心代码实现完了吗?
答案是,实现完了!也就是说,子进程早在 return前就创建好了,并且可能已经在 OS的运行队列中,准备被调度了。对应的,当代码运行到 return时,会有父进程、子进程两个进程各自执行return。
(2)如何理解 fork返回后,给父进程返回子进程的 pid,给子进程返回 0?
因为一个父亲的孩子可以有很多个,可是每个孩子都只有一个父亲。也就是说,孩子找父亲是具有唯一性的。以此类推,子进程 fork之后,不需要父进程的 id值,因为父进程具有唯一性。而父进程 fork之后需要对应子进程的 id,因为该父进程可能不止一个子进程,它需要对应的子进程 id做标识。
(3)如何理解同一个 id值,会返回两个不同的值,让 if 和 else if 同时执行
返回的本质:就是写入。我们不知道父子进程谁先返回,谁先返回,谁就先写入 id值。由于进程具有独立性,进程在执行 fork相应代码时,会在操作系统内部进行写时拷贝,使 fork对应的进程可以返回两个不同的值,再让对应的父子进程根据自己返回的 id,去执行 if 或 else if 中的代码内容。
(4)理解写时拷贝
通常情况下,父子代码共享,父子进程在不写入(不修改共享部分的数据)时,对应的数据也是共享的。当任意一方试图写入,操作系统便会以写时拷贝的方式,给需要修改的一方在物理内存中开辟一块新空间,将原来的数据拷贝到新空间中,再对新空间中的数据做修改。具体见下图:
———— 我是一条知识分割线 ————
3.fork常规用法
- 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
- 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。
4.fork调用失败的原因
- 系统中有太多的进程
- 实际用户的进程数超过了限制(一个用户可以创建的进程是有限制的)
二、进程终止
1.进程退出码
这里给大家讲解一下进程退出码,我们知道写代码是为了完成某件事情,那我们如何知道这件事完成的怎么样呢?我们可以通过进程退出码来了解。
进程在退出时,会有对应的退出码,标定进程执行的结果是否正确。
退出码的意义