对进程的初步认识以及fork()函数的理解

本文围绕Linux进程展开,介绍了进程是运行到内存的程序,操作系统通过进程PCB管理进程。阐述了Linux下进程PCB的结构体形式,以及进程id的查看方法。还介绍了进程查看的指令,如ps axj和ls/proc。最后讲解了Linux中进程的创建方式,包括命令行启动和使用fork函数创建子进程。

什么是进程 

进程是什么呢?其实解释的通俗浅显一点就是我们运行到内存的程序。我们知道运行一个磁盘里的程序时,会将该程序先加载(将磁盘的数据拷贝)到内存当中,因此该程序就可以称为一个进程。首先我们以Windows操作系统为例, 可以快捷键查看当前正在运行的进程:Ctrl+shift+Esc

进程PCB 

 其实在程序加载到内存之前操作系统这个软件早早的就已经加载到内存当中,而当你双击运行程序加载到内存的过程都是操作系统帮你完成的,而你的内存当中肯定不止有一个进程,所以此时操作系统就需要对你的进程做管理。而管理进程并不是管理这款运行起来的软件,而是管理该进程的PCB(process control block)进程控制块。而对进程PCB的理解是这样的,想要管理进程肯定需要该进程的各种属性以及实时状态,所以操作系统就将该进程以一个结构体的形式存储好该进程的所有属性,而该结构体就称为进程PCB。每一个进程都有对应的PCB,最终都由操作系统进行管理。而cpu处理进程时,拿到的就是进程对应的PCB。


所以最终我们就可以初步了解:进程=可执行程序( 代码和数据)+内核数据结构(PCB就是其中之一,方便OS对进程管理) 

 Linux下的进程PCB

我们知道每个进程都有对应的PCB,而PCB其实是一个统称,就像Linux下的进程PCB具体就是struct task_struct的一个结构体。其实每个进程的PCB都是通过类似于双链表的形式衔接起来得,所以可以说,每个人进程的PCB还存放着两个指针,分别指向前后两个节点的数据。

进程id

而这个struct task_struct(Linux下的PCB)存放的核心数据有哪些呢?自然少不了每个进程对应的标识符:pid(进程id)以及所属标识符:ppid(父进程id)

对一个进程的pid 查看可以用getpid指令,而对一个进程的父进程查看可以getppid指令。


但是有一点:每次运行同一个进程时,该进程的id都会发生改变,但是父进程id却不变

 其实我们的命令行当中,父进程一般都是命令行解释器:shell(Linux下的bash)

所以当我们在命令行中输入的所有指令,运行的程序时,对应的父进程都是bash。

 


进程查看 

1

对进程的查看可以采用 ps axj 指令,查看当前进程。所以可以进行测试:

倒计时的一个程序:

执行结果: 

 运行结果如上,我们知道可执行程序运行起来就算是一个进程了,所以进行查看该进程时就可以查看到,而一旦运行结束,该进程也就没了。

2

还可以通过ls/proc查看所有进程,proc其实就是根目录结构下的一个动态目录结构,该目录下存放着所有存在的进程,而proc下的各个目录都是以存在的进程id命名的,而这里面的内容就是关于对应进程在内存当中的信息以及属性等数据。

这里其实有一个进程属性需要提一下,cwd(当前工作目录),默认情况下,进程启动所处的路径就是当前路径。可以通过chdir()函数更改当前进程的工作目录

Linux中进程的创建

  1. 命令行中直接启动进程
  2. 通过代码来创建进程

其实启动进程的本质就是创建进程,而进程一般是以父进程为模版创建的,进程大部分的属性与父进程相同,只有少部分不同于父进程。

初识fork()

通过代码来创建子进程,就要使用到fork函数,这是一个系统调用。

所以在调用fork函数,只有父进程会执行上面的代码,fork之后会以当前进程(父进程)为模版创建子进程,之后系统会执行两个进程,也就是父子进程一起执行。而且该函数会为父进程返回子进程的pid,为子进程返回0。如果fork失败的话就不会创建子进程,则会为父进程返回-1。

测试用例:

执行结果:不断循环

这个执行结果肯定会充满很多疑问???

前言:

执行可执行程序会先将程序加载进内存中,其实在fork函数的内部会以父进程为模版创建子进程,也就是会将父进程的大部分属性都拷贝到子进程的PCB中。然而子进程并不是从磁盘来的,而是在内存创建的,所以父子进程会共享代码,也就是子进程与父子进程指向同一份代码,但是内部的数据却是独立成各自一份(为了防止一方数据修改而影响另一方的执行结果)。进程之间具有独立性,尽管是父子进程,删除一个进程并不会影响另一个进程,并且进程指向的代码是只读的,并不能做任何的修改,不会受到PCB的影响。

但是为什么子进程不会执行fork之前的代码呢??

其实代码是按照顺序依次执行的,执行当前代码时,操作系统内部寄存器(eip)每次都会保存下一次执行的代码数据,所以fork系统调用执行之后会分流,所以eip指向的就是fork之后的代码,而eip这样的程序计数器也会被子进程继承,所以子进程记录的读写位置就是fork之后。

为什么变量i接受了两个返回值??

fork函数内部会为子进程创建PCB,将父进程的核心代码数据都拷贝给子进程,最后返回。但是实际并不是在fork函数完全执行完以后发生分流的,而是在执行完fork的核心代码之后就已经分流了,所以fork的return会被执行两次,分别为父子进程返回相应的值。     

返回实际就是写入数据 ,将数据写入变量i中,而变量i起初是父进程定义的变量,属于数据,而父子进程数据独立私有,避免数据量过大,造成空间浪费,所以满足写时拷贝特性,因此返回的时候发生了写时拷贝 ,导致同一个变量会有不同的值。                            


请读者按照下面的步骤使用 fork 函数编写一个可以创建多个子进程Linux 0.11 应用程序,一方面 可以学习 Linux 的多进程编程技术,另一方面,通过观察多个进程的运行过程,可以对进程的调度过程有 一个初步认识。 id 1. 使用 VSCode 打开之前克隆到本地的 Linux 0.11 应用程序项目。 2. 打开 linuxapp.c 文件 main 函数,让父进程新建三个子进程,并分别输出子进程 id 及其父进程 。代码如下: int main( int argc, char * argv[] ) { if( 0 == fork() ) { printf("child process pid=%d ppid=%d line=%d\n", getpid(), getppid(), __LINE__); } else if( 0 == fork() ) { printf("child process pid=%d ppid=%d line=%d\n", getpid(), getppid(), __LINE__); } else if( 0 == fork() ) { printf("child process pid=%d ppid=%d line=%d\n", getpid(), getppid(), __LINE__); } else { wait( NULL ); printf("parent process pid=%d ppid=%d\n",getpid(), getppid()); } return 0; } 其中,getppid 函数可以在子进程中获取父进程的 id。“__LINE__”是 GCC 编译器提供的一个预 定义宏,它的值是其在源代码文件中的行号。 3. 不能在 VSCode 中按 F5 启动调试 Linux 0.11 应用程序。只能在 VSCode 的“Terminal”菜单中选 择“Run Build Task...”,会在 VSCode 的顶部中间位置弹出一个可以执行的 Task 列表,选择其 中的“Bochs 运行(不调试)”。 4. 待 Linux 0.11 启动完毕后,将生成的可执行文件从软盘 B 拷贝到硬盘,命令如下: mcopy b:linuxapp.exe app 5. 为 app 文件添加可执行权限,命令如下: Linux 内核实验教程 chmod +x app 6. 执行“sync”命令确保 app 文件写入硬盘。 7. 使用命令./app 运行可执行文件 app,观察各个进程开始执行的顺序和结束执行的顺序,理解进 程在其生命周期中状态的转换过程和进程调度过程。 8. 结束调试,关闭 Bochs 虚拟机。
05-29
根据原作 https://pan.quark.cn/s/0ed355622f0f 的源码改编 野火IM解决方案 野火IM是专业级即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。 主要特性有:私有部署安全可靠,性能强大,功能齐全,全平台支持,开源率高,部署运维简单,二次开发友好,方便与第三方系统对接或者嵌入现有系统中。 详细情况请参考在线文档。 主要包括一下项目: 野火IM Vue Electron Demo,演示如何将野火IM的能力集成到Vue Electron项目。 前置说明 本项目所使用的是需要付费的,价格请参考费用详情 支持试用,具体请看试用说明 本项目默认只能连接到官方服务,购买或申请试用之后,替换,即可连到自行部署的服务 分支说明 :基于开发,是未来的开发重心 :基于开发,进入维护模式,不再开发新功能,鉴于已经终止支持且不再维护,建议客户升级到版本 环境依赖 mac系统 最新版本的Xcode nodejs v18.19.0 npm v10.2.3 python 2.7.x git npm install -g node-gyp@8.3.0 windows系统 nodejs v18.19.0 python 2.7.x git npm 6.14.15 npm install --global --vs2019 --production windows-build-tools 本步安装windows开发环境的安装内容较多,如果网络情况不好可能需要等较长时间,选择早上网络较好时安装是个好的选择 或参考手动安装 windows-build-tools进行安装 npm install -g node-gyp@8.3.0 linux系统 nodej...
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CR0712

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值