0
点赞
收藏
分享

微信扫一扫

【校招 --阶段一 系统编程】进程控制

静悠 2022-02-18 阅读 127

一、进程创建
fork函数初识

在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。

fork()创建进程是以父进程为模板的
进程调用fork,当控制转移到内核中的fork代码后,内核做:

  • 分配新的内存块和内核数据结构给子进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 添加子进程到系统进程列表当中
  • fork返回,开始调度器调度

fork()之前为一个进程,而之后为两个进程,
在这里插入图片描述
当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以
开始它们自己的旅程,看如下程序。

#include<iostream>
#include<stdlib.h>
#include<unistd.h>
using namespace std;
int main(){
cout<<"我是父进程 pid为:"<<getpid()<<endl;

pid_t id=fork();
if(id==0){


cout<<"我是子进程 pid为:"<<getpid()<<endl;
sleep(1);
}else if(id>0){
cout<<"我是父进程 pid为:"<<getpid()<<endl;
sleep(1);
}

return 0;
}

在这里插入图片描述

fork()之后子进程为什么会执行fork()之后的为什么没有从fork()之前执行?

在这里插入图片描述
所以,fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器
决定。
子进程在创建时将父进程部分数据结构内容拷贝至子进程,而父进程也将程序计数器拷贝给了子进程,所以父子进程是从同一个地方开始执行的。

fork函数返回值

子进程返回0,
父进程返回的是子进程的pid。

为什么fork()有两个返回值?

cout<<"我是父进程 pid为:"<<getpid()<<endl;

pid_t id=fork();
if(id==0){


cout<<"我是子进程 pid为:"<<getpid()<<endl;
sleep(1);
}else if(id>0){
cout<<"我是父进程 pid为:"<<getpid()<<endl;

在这里插入图片描述
当执行fork()时进入内核 fork()前边的代码由内核实现,而retrun语句有进程执行,当前边的有内核执行完进程已经创建完毕,已经开始执行了,而return语句分别有父子进程执行当父进程执行时返回的是子进程的pid,子进程执行时返回的是0。

写时拷贝

默认情况下。父子进程共享代码,但是数据各自是有一份!
代码共享:所有代码共享,不过一般都是从fork()之后开始执行,为什么代码是共享的?代码是不可修改的,所以各自私有一份浪费空间
数据为什么是私有的?因为进程之间具有独立性。数据是很多的,不是所有的数据都立马要使用,且不是所有的数据都需要拷贝。但是如果立马要独立,就需要将数据全部拷贝下来,把本来可以可以后边拷贝,甚至不需要的数据,都拷贝下来
就浪费时间和空间。这就有了写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副
本。具体见下图:

在这里插入图片描述
创建子进程时将父进程的数据结构拷贝给子进程,所以父子进程页表指向的物理内存地址也一样。
在这里插入图片描述
当子进程五王数据段写入数据时,因为父子进程的数据段对应的物理内存地址时共享的,为了不影响父进程会重新开辟一段空间,调整映射关系。写时拷贝是由os完成

问题:

  • 1 写时拷贝什么时候用
  • 原理是当父进程创建子进程时 页表将对应的代码段和数据段上设置为只读状态,当写入数据时。
  • 2 如何理解子进程创建?如何理解fork()?
    本质就是多了一个进程,子进程要以父进程为模板

二、进程终止
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止

进程常见退出方法

正常终止(可以通过echo $? 查看进程退出码):

  1. 从main返回
  2. 调用exit
  3. _exit

异常退出:

  • ctrl + c,信号终止

_exit函数

说明:虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值
是255。

exit函数

exit最后也会调用exit, 但在调用exit之前,还做了其他工作

1 执行用户通过 atexit或on_exit定义的清理函数。
2. 关闭所有打开的流,所有的缓存数据均被写入
3. 调用_exit

在这里插入图片描述

return退出

return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返
回值当做 exit的参数。

举报

相关推荐

0 条评论