Linux之初见进程

发布于:2025-05-14 ⋅ 阅读:(13) ⋅ 点赞:(0)

1. 冯诺依曼体系结构

冯诺依曼体系结构是计算机的基本设计原则之一,也被认为是现代计算机的基础。它由美国数学家约翰·冯·诺伊曼在20世纪40年代后期提出。冯诺依曼体系结构包括存储程序概念、将数据和指令存储在同一存储器中、按照顺序执行指令等关键特征。

具体来说,冯诺依曼体系结构包含以下几个主要组成部分:

  1. 存储器:用于存储数据和指令,包括内存和外存。

  2. 运算器:负责执行各种算术和逻辑运算。

  3. 控制器:负责指挥整个计算机系统的运行,包括指令的执行和数据的传输。

  4. 输入设备:用于将数据输入到计算机系统中。

  5. 输出设备:用于将计算机处理后的结果输出。

画成图就是以下这样:

其中,cpu包含运算器和控制器。 

冯诺依曼体系结构的优点在于其设计简洁、易于实现和扩展,适用于不同类型的计算任务。现代计算机系统普遍采用冯诺依曼体系结构作为基础,这使得不同计算机之间能够进行数据交换和通信。

我们在第一次接触冯诺依曼体系结构都会想,明明干活的是运算器和控制器。那么我们为什么要加一个存储器呢?简单来说呢就是cpu的速度太快了,我们需要帮cpu把数据都提前搜集起来,然后让cpu来算,在多任务场景下,可以大大的提高计算机的效率。当然存储器还会帮cpu整理数据,起到一个缓冲的作用。同时还降低了计算机的成本,所以说存储器是必要的。

2. 操作系统

2.1 操作系统的存在原因

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。简单的来说,操作系统就是内核(进程管理,内存管理,文件管理,驱动管理)加上其他各类程序(如函数库,shell程序等等)。

我们之所以要在计算机里面装操作系统一是为了提高用户的操作体验,二是为了更加高效的管理软硬件,提高计算机效率(因为操作系统就是在专门用来管理的系统)。

那操作系统到底是怎么管理的呢?

操作系统的管理方式就类似于中间人传话,我们用户先把自己想要干的事告诉给用户操作接口,然后用户操作接口再把我们的诉求告诉给系统调用接口系统调用接口再把诉求告知操作系统,最后操作系统去执行我们的合法诉求(为什么说是合法,这是因为不合法的诉求根本传不到操作系统)。

画成图就是以下这样:

 最下面那个软硬件简单来说就是驱动程序和计算机底层的硬件。

那么我们为什么不可以直接在操作系统上进行操作呢,这是因为操作系统并不相信我们用户,同时这样做对计算机来说比较危险。举个例子,如果说现在电脑C盘有100个G,然后我们直接访问操作系统并告诉他其实你只有40个G,那么那60个G可能就永远丢失了,所以说这是一种风险极高的操作,所以为了让我们规范的使用计算机,于是就有了用户操作接口系统调用接口。

2.2 操作系统对硬件的管理

为了方便管理计算机的硬件资源,操作系统会建立一个个的struct结构体并将其以链表或者其他高效的数据结构来进行串联。

当然他并不是简单的直接一个指针指向下一个来进行连接的。我们以链表为例子,

我们来看下面这张图片里面的红色箭头指向的那个式子,我们就是通过改变那个start来实现遍历访问的,在这个公式里面,链表操作只知道 struct node *start,不知道这是哪一个 task_struct 的 link 成员(task_struct *)0 是构造一个假地址为 0 的指针,它的 ->link 的地址就代表偏移量本质就是start 是一个 struct node *,而不是 task_struct *,根本没 other 这个字段!必须先转换回 task_struct* 才能访问它的其他成员。

简单来说那个0实际上用来是锁定是哪一个链表,然后那个start就相当于是这个链表的哪个位置
 

2.3 系统调用接口和用户操作接口区别

系统调用接口就是操作系统为了上层考虑然后开放自己的部分接口用于和上层进行链接。他的本质我们也可以理解为操作系统的一部分。

而用户操作接口就不一样了,它的本质我们可以理解为为了用户可以间接调用操作系统而设计的接口,当然不同的语言也有不同的用户操作接口,我们也可以叫它们为库函数。

PS:虽然用户操作接口有很多个,但是它们都是指向了同样的系统调用接口。

3. 进程

3.1 进程概念

进程简单来说就是一个个正在跑的程序或者一个个执行实例等等。

3.2 PCB

要理解进程我们就会谈到一个概念叫做PCB,我们也可以叫它task_struct。

那么什么是PCB呢?简单来说就是相当于一块存储着代码或者说进程信息的一个结构体。我们之所以会用到这个本质上是因为程序是一个个执行的(单核计算机)。那么我们就需要对代码进行排队,但是直接让代码或者说进程去排队的话会影响计算机的速度,所以我们创建了task_struct,让它代替进程去排队。

PS:虽然说是一个个执行,但是并不是一次就直接完成的,举个例子,可能是每个代码跑0.0000001秒就换一个代码跑。同时由于计算机的计算速度很快,所以在我们看来就是很多个代码同时在跑。

举个例子,就相当于我们在手机上卖奶茶,我们还有好几杯在做,那么这个时候就是我们的这个奶茶的订单号在系统里面排队,不然的话我们就要在现实里面一个个排好队拿奶茶。

task_struct里面大概就存储了以下数据:

标示符: 描述本进程的唯一标示符,用来区别其他进程。

状态: 任务状态,退出代码,退出信号等。

优先级: 相对于其他进程的优先级。

程序计数器: 程序中即将被执行的下一条指令的地址。

内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针

上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。

I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。

其他信息......

PS:这个上下文数据简单来说就相当于在进程上下文切换时,保存当前进程处理器寄存器中的数据,防止数据丢失 。当进程重新被调度执行时,能恢复这些数据,让进程继续之前的执行状态,确保多进程并发执行的正常运转 。这边要注意和程序计数器做区分。

4. 父子进程

4.1 父子进程概念

父子进程简单来说就是父进程要做某一件任务,但是它并不会自己去做,而是会生成一个子进程,这个子进程会和父进程共享代码,但是在数据上会自己生成一份(这是为了防止污染原数据),然后这个子进程会去执行这个任务。

同时当子进程完成任务的时候,父进程会对子进程进行回收。

子进程有各种各样的状态,以下是他的一些状态类型:

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。

D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

4.1.1 僵尸进程

有进程叫做僵尸进程即(Z进程),就是指子进程结束后父进程没有对其进行回收时的一种状态。这个状态会导致内存泄漏问题,如果父进程一直不来回收,那么子进程就会一直处于僵尸状态。

4.1.2 孤儿进程

还有一种进程叫做孤儿进程,它本质是僵尸进程的一个分支,就是指一个字进程的父进程已经没了但是子进程这个时候才刚刚完成任务,导致其无法被父进程回收,这个就叫做孤儿进程。但是如果说是这种情况那么我们是不用特别担心的,因为1号进程(init进程)会领养孤儿进程。

5. 进程优先级概念

我们知道进程会在cpu上轮着跑,那么如果说一个进程很重要难道也要一直排队吗。所以这个时候我们就引入了一个概念叫做进程优先级。

这个方式可以大大的改善计算机的性能,因为可以重要的先做,不重要的放在后面做。

我们输入ps -l就可以进行查看,我们来看下面这个代码,我们可以看到UID,PID,PPID,PRI和NI。

UID的话就是指的执行者身份,0表示root账号(也就是超级用户),然后大于1000的都是指普通用户。

PID就是指一个进程的代号,而PPID就是指当前这个进程的父进程代号。

PRI就是指当前这个进程的的优先级,这个数字越小那么它的优先级就越大。这个数字最大到100,最小到60。

NI就是代表这个进程的nice值(这个值大小在-20到19,这个值加上80就是PRI了)。

PS:nice值不是优先级,但是nice值是影响优先级的重要因数。

那如果我们想要更改nice那么应该怎么做呢?我们可以先按top,然后就可以进入这个界面。

接着我们输入r,就会出现下面红色箭头指向的一行,然后输入想要修改的那个进程的PID,接着在输入想要修改的nice值就好了。

记住输入的是nice值,不是PRI。

6. 其他概念

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行(这个指的是多核的计算机)。

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。


网站公告

今日签到

点亮在社区的每一天
去签到