实用指南:Linux操作系统之进程控制(1)
1、进程创建
复习fork函数,fork函数的返回值
fork函数是创建一个子进程,也就是当前的父进程创建一个新的子进程
整理一下就是:新的进程是子进程,原来的进程是父进程
#include
#include
int main()
{
printf("I am a process:%d\n",getpid());
pid_t id=fork();
if(id<0)
{
//进程创建失败!
printf("fail fork!\n");
return 1;
}else if(id==0)
{
//child
printf("I am a child:%d\n",getpid());
}else{
//parent
printf("I am a parent:%d,my son pid:%d\n",getpid(),id);
}
return 0;
}
fork调用进程,那么进程在内核中做了什么?
1、开辟新的内存块和内核数据结构给子进程
2、将父进程部分内核数据数据拷贝到子进程
3、将父进程的PCB、地址空间、页表相关内容也都复制拷贝到子进程中,但是只有pid不是复制
4、将子进程添加到系统进程列表中
5、fork返回,开始调度器调度
为什么fork有两个返回值?
你举手(调用fork()系统调用)
监考老师(操作系统)过来:
记下你的当前答题进度
叫来一个新考生(创建子进程)
给新考生一份空白的答题卡,但题目册和你共用一本
悄悄告诉你:"他的考号是1001"
悄悄告诉他:"你的考号是0"
你们继续考试:
你看你的题册,他看他的题册(同一本物理书)
你在你的答题卡写:助手考号=1001
他在他的答题卡写:我的考号=0
当你想在题册上做标记时:
监考老师立刻复印该页,给你新的一页
你在新页上做标记
他如果也想标记,老师会复印原页给他新的一页
同理,
1、fork进入内核
2、fork函数的实现进行申请内存构建数据结构PCB,虚拟内存,页表,最后将当前新进程设置为R状态,放置进调度列表中
3、此时进程已经创建成功了,父子进程共享代码,fork函数的最后一个代码是返回一个值,return ret这个代码父子进程都会执行一次
所以会有两个返回值 在返回时,将函数的返回值返回给变量,发生了写时拷贝,一个变量名但是内容是不同的,本质父子页表映射数据到了不同的内存区域
写时拷贝
例如
父亲账户是一千元
儿子想在父亲账户取两百块钱!
银行说:不行,你不能在你爸爸账户上拿,请你立刻开一个账户,把你爸爸的一千元复制过去
儿子在新账户上操作,取了两百,余额800
父亲的账户没有变
结果:父亲的是一千(原账户),儿子的是八百(新账户)
#include
#include
int main()
{
int data=1000;
pid_t id = fork();
if(id==0)
{
//儿子开始取钱,取完剩下800
printf("儿子:我看到:%d\n",data);
data=800;
printf("儿子:我要取钱了,还剩下:%d\n",data);
}else{
//父亲检查
sleep(1);//儿子先拿
printf("父亲:儿子拿完之后,我的钱剩下:%d\n",data);
}
return 0;
}
操作系统上的解释:
物理内存变化: 初始(fork后): 父子都指向同一物理页,页面标记为"只读" 儿子写操作时: 1. CPU:"哦,这个页面是只读的" 2. 触发缺页异常 → 进入内核 3. 内核:"这是COW页面,要复制" 4. 分配新物理页,复制内容 5. 修改儿子页表:指向新页面,设为可写 6. 儿子继续写操作 结果: 父亲页表 → 原物理页(内容未变) 儿子页表 → 新物理页(修改后的内容)
进程调用失败的原因
系统有太多进程
实际用户的进程超出了限制
总结:本质是以父进程为模板创建了子进程,不是所有的子进程都复制父进程,例如PID就不是一样的
2、进程终止
进程共有三种退出场景
1、代码跑完了,结果是对的
2、代码跑完了,结果是不对的
3、代码没跑完,程序退出了(代码异常终止)
情况1和2退出的时候会有退出标志,而情况3是发生了异常会有退出的原因
进程常见退出码
int main()
{
return ?;
}
return 后面跟着的数字就是进程的退出码
echo $?是可以查看最近一次的进程退出码
查看进程码的信息
#include
#include
int main()
{
for(int i = 0;i<200;i++)
{
printf("%d:%s\n",i,strerror(i));
}
return 0;
}
exit和return的区别
exit:终止整个进程,任何地方调用,都会终止
return:终止函数,如果main函数return,代表终止整个进程
站在OS角度,如何理解进程终止?
进程终止的本质
进程终止的核心思想就是归还资源:
1. 释放进程管理数据结构
不是真的销毁数据结构对象,而是将它们标记为“空闲”状态,放回对应的数据结构对象池中。这样后续创建新进程时可以直接复用这些已分配的内存块,避免频繁的内存分配开销。
2. 释放程序代码和数据占用的内存空间
不是把内存内容清空,而是将相关内存页标记为“无效”,从进程的页表中移除映射关系。这些物理页面可以被其他进程重用。
3. 取消进程间的链接关系
解除进程与父进程、子进程、进程组等之间的关联关系,更新相关的内核数据结构。

浙公网安备 33010602011771号