进程(1)——什么是进程?【linux】

本文详细介绍了Linux中的进程概念,包括进程的定义、管理机制(如PCB和task_struct),以及查看进程的方法(ps和ls/proc)。重点讲解了fork()函数创建父子进程的过程,探讨了返回值的意义和数据共享的策略。
摘要由CSDN通过智能技术生成

一. 什么是进程?

概念:正在运行的程序
还记得前面讲的冯诺依曼结构吗。

系统的软件和硬件
那里面我们讲了,输出设备和输入设备的数据交互基本都是和内存的
之后cpu从内存中读取数据,在内存中被读取到的程序就可以看作在运行
所以通俗的讲:一个已经加载到内存中的程序,就叫做进程

同时一个操作系统能运行多个进程,这个想必大家也知道
因为在现实中,我们能一边听歌一边玩游戏就是多个进程并行

二. 管理进程:

我们了解了什么是进程后,就要来了解了解
在系统中是如何管理内存中的一个个程序的

2.1 怎么管理:

这里我们要明确一个点:

我们是要对运行的程序进行管理,因为内存中有多个运行程序
我们的管理想法:是对各个运行程序能进行查看和改变他们的状态

但是光靠程序本身的代码和数据不能进行管理

就比如写了一个test.c其中有hello world的程序

当被读取到内存中的时候,还有很多个相同的程序
那如何进行区分,如何找到运行程序在内存中的地址?

这些问题程序本身的数据和代码不能解决的。

所以我们就需要自己给程序添加一些属性
1.程序在内存中运行的编号(进程编号
2.程序在内存中的地址
………………
等等

所以说进程不光是被读取到内存中的程序,同时还有为了方便管理而添加的属性
在这里插入图片描述
这里我们了解了进程的具体组成后,我们就可以聊聊该如何进行管理了。

这里有一个口诀:先描述再组织

描述:
我们之前做数据结构时,都是先想好管理的类是如何构成的
比如说为了写个学生管理系统,需要在类中塞进学生的各个信息的属性。
组织
管理的类什么样子想好后,就可以进行组织,挑选用什么结构去进行组织管理,链表,顺序表等
系统中的硬件都是这样进行管理的,所以操作系统中有大量的数据结构

所以说进程也是一样,但是进程是在系统中的,系统使用C语言写的,所以不是类,而是结构体

所以进程也是塞进数据结构中的,进程可以说是一个数据结构结构体对象

所以这里我们就能组织一下进程是啥了

在这里插入图片描述
这里将pcb与数据和代码分开是因为:
pcb是管理进程所需要的

代码和数据在管理进程的时候实际上是用不到的

2.2 PCB

将管理进程所需要的属性进行描述后,就是pcb

PCB是描述进程属性的一个数据结构结构体对象。
PCB结构体中包含了:
1.进程编号
2.进程状态
3.优先级
…………
所以对进程进行管理,就是对PCB进行管理
虽然PCB组织方式有很多,但基本上都是链表,所以管理PCB的本质就是对链表的增删查改

这里画了一个图让大家理解
在这里插入图片描述

2.3.1 task_struct

在linux中PCB是:task_struct
task_struct 是pcb的一种
属于linux内核中的一种数据结构体对象
创建一个进程就是对task_stuct的实例化

2.3.2 组织task_struct:

linux如何组织进程:
linux内核中,最基本的组织进程task_struct的方式,采用双线链表组织
task_struct本身在双链表中
同时双链表可能处于别的数据结构组织中,所以关系错综复杂
将上面的pcb图换成task_struct就行
在这里插入图片描述

三.查看进程

接下来就该查看系统中的进程了。

这里带来查看进程两种方法:

3.1 ps ajx

ps ajx

在这里插入图片描述
这里我们看到了多个进程
同时能看到:ppid pid等进程属性

这里小提一下,上面说了pcb本质在链表中,所以ps本质也是遍历链表

ps ajx | grep 文件名 查找进程:

在这里插入图片描述
这里我们发现第二个进程是grep test
正好是我们执行的代码,这是因为执行grep操作时,grep本身也变成了一个进程。

3.2 ls /proc

ls /proc

在这里插入图片描述
这里我们能看到大量的数字
这是因为:在proc目录中会给每一个正在运行的进程创建一个以他们的(进程编号)pid进行命名目录
同时:目录中有进程的属性,当进程结束了以后proc中的文件会进行对应进程的文件夹删除。

查看进程属性名

ls /proc/进程pid -l

在这里插入图片描述

这里注意一下这个cwd
(current work dir)cwd:当前进程的工作目录(进程启动时,记录下来的文件所在目录)
这就是有时候用部分文件操作指令时,不需要输入目录,而是默认在当前文件的目录下执行,这是因为进程记录了当前的运行目录

四. 父子进程

4.1 什么是父子进程

pid:进程编号,每个进程都有属于自己的编号,便于管理

获得自己的pid:

getpid

在这里插入图片描述

在这里插入图片描述

ppid 父进程:可以认为时父进程中衍生出来的子进程

getppid

用法与子进程一样

这里我们让他们进行父子同台一下。
在这里插入图片描述
用这个文件进行测试一下。
在这里插入图片描述

这里能发现每一次重新执行程序,父进程编号不变,子进程编号会变

这里我们来查看一下父进程是谁

ps axj | head -1 && ps -axj | grep 16668

这里&&代表两边指令都要执行

搜索出来:
16668是bash进程
在这里插入图片描述

bash是命令解释器,相当于充当用户和系统的中介,这个在之前的博客提到过。

我们所有在命令行打出的指令的父进程可以说都是bash的子进程

4.2 创建子进程——fork()

fork()创建一个子进程——代码级别创建子进程
这里的fork不同于我们平常在指令出用的 ./
fork是在代码处使用的。

4.2.1 用法

在这里插入图片描述

在这里插入图片描述
这里我们能发现这后面的lala,多打印了一遍。
说明创造出来的子进程,是从创造出来的位置执行代码的

fork具有返回值:
在父进程中,fork返回新创建子进程的进程ID;
在子进程中,fork返回0;
如果出现错误,fork返回一个负值

这里我们就用这个文件进行测试一下
在这里插入图片描述
在这里插入图片描述
这里我们可以提出三个疑问了

1.为什么要给子进程返回零,给父进程返回pid
直接返回一样值不行吗?

2.fork怎么返回两次
fork明明就是一个函数是怎么做到返回两次的。
让父进程和子进程都接收到值

3.一个变量怎么会有不同的值
这个返回值为什么有不同的情况

4.2.2 刨析fork三个疑问

i. 为什么要给子进程返回零,给父进程返回pid

从前面我们知道fork之后的代码子进程和父进程共享
但是我们创建父子进程就是为了让他们干不同的事

因为fork之后代码共享,所以为了区分子进程和父进程,来让两个进程进入执行不同的代码,
所以返回不同的返回值,区分不同的进程流,执行不同的代码块(加了筛选条件,if while等)

ii. fork怎么返回两次

要回答这个问题的话需要了解fork这个函数到底是如何执行的。、

当在fork中将pcb创建完了后,
子进程就已经成为一个单独的进程,能被系统进行调用。
所以执行return的语句之前,子进程和父进程就已经代码块共享了
所以能执行return语句,就返回了两次。

iii. 一个变量怎么会有不同的值:

这里也可以理解为:
子进程和父进程的数据(变量)到底共享还是独有

因为进程的组成有:
数据和代码+pcb
两个进程的pcb已经复制,代码共享

接下来就是数据:

对于进程来说每个进程都具有独立性,都能单独进行运行
数据可能被进行修改,所以为了不影响两个进程的数据导致代码运行(保证进程独立性),所以两个进程的数据不能进行共享

所以子进程和父进程的数据是独立的,但是如果父进程有大量的数据,可能子进程压根就用不上,就会导致大量的内存流失

所以在最开始的时候父进程和子进程数据代码都是共享的
但是当子进程尝试去修改父进程的变量时候,编译器会创建一个对应变量的空间,同时给子进程专门拷贝父进程对应的变量

可以称为写时拷贝

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想学c啊啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值