【Linux】:体系结构与进程

朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux体系结构和进程的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

目录

1. 冯诺依曼体系结构

2. 操作系统

2.1 概念

2.2 关于管理

2.4 总结

3. 系统调用

4. 进程

4.1 基本概念

4.2 描述进程

4.3 task_struct核心字段

4.4 ps ajx指令

4.5 getpid系统调用 

4.6 kill指令


1. 冯诺依曼体系结构

我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。

  • 计算机里面几乎所有的设备,都具有存储数据的能力。
  • CPU处理数据的能力是非常快的,其次是内存,然后是各种外设。

为什么各种计算机、服务器大部分都要遵守冯诺依曼体系呢?

以CPU为中心,距离CPU越近的,存储效率越高,造价越贵。

那么这些存储器有存储效率与存储速度的区别,那么为什么不全都使用存储效率最好的存储器来组成计算机呢?

理论上是可以的,但是最关键的一点就是:太太太贵了!!!,因为计算机是需要大部分平民百姓去使用的,并不是只有一少部分富豪来使用,但如果都是用最为便宜的存储器来组成,那么造出来的计算机基本不能用,所以需要进行取中,在兼具性能的同时,也需要注意造价。

基于冯诺依曼体系结构的计算机的本质就是:用较少的成本,打造出来效率不错的计算机。

2. 操作系统

2.1 概念

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。大体的理解,操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等等)

我们的计算机在开机时第一个加载的软件就是操作系统,它是一款软件,进行软硬件资源管理的软件。

为什么要有操作系统?

手段:操作系统将软硬件资源管理好。

目的:给用户提供良好(安全、稳定、搞笑)的使用环境。

2.2 关于管理

在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件。
操作系统内部,一定会存在大量的数据对象和数据结构。那么OS是如何管理各种各样的数据呢?
在操作系统的内部,各种数据信息都是以一种数据结构--链表来进行存储管理的,链表中的每一个节点存储各种信息的属性,通过节点的指针将各个信息属性的节点连接起来,这样子就通过对链表的增删查改来实现对各种信息的管理。

2.4 总结

计算机管理硬件

  • 1. 描述起来,用struct结构体
  • 2. 组织起来,用链表或其他高效的数据结构
  • 3. 简要概括为:先描述,再组织

3. 系统调用

  • 在开发角度,操作系统对外会表现为一个整体但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
  • 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。

首先我们需要了解一下操作系统管理的核心:

  • 进程管理
  • 内存管理
  • 文件/IO管理
  • 驱动管理

那么关于管理方面总结出来的就是:“先描述。再组织

我们可以再将操作系统的层状结构拿过来看一下:

可以看到在用户到操作系统这一环节其中还是需要经过两层结构,那么为什么用户不能直接的去访问操作系统呢?

那么这里就涉及到一个安全的问题,对于操作系统来说,它是不相信任何一个人的,无论是谁,但是呢,它也要为我们做各种事情,那么就需要用到上述提到的OS暴露出来的一部分接口:系统调用接口。用户首先使用用户操作的接口来根据所需让系统调用接口去与操作系统进行交互,使得操作系统做出对应的操作。

在现实中也存在类似于操作系统与用户这样的例子,比如:银行与办理业务的社会人员,银行不会直接让你操作银行的资源系统,而是开放对应的窗口,设置对应的工作人员,你只需要将你的意愿转达给业务人员,那么他们就会实施对应的操作。

注意:

一般一个用户想要访问非常底层的OS数据或者访问硬件,都必须贯穿于整个层状结构。(用户必定要调用系统调用)

所以在我们使用语言级别的代码,比如使用printf、cout往显示器上面打印数据时,就相当于访问了底层硬件,因此,这些语言级标准库必定封装了系统调用!

系统调用,由于是OS提供的借口,所以使用起来比较麻烦,因此站在使用系统的角度:通过了一个外壳程序,这个程序在Linux里面就是shell,在Windows里面就是图形化界面。

这个外壳程序也是程序,使用C/C++语言写的,一定调用了系统调用。

那么站在在系统上开发人的角度:可以直接调用系统接口,那么不仅仅是使用者有可能为小白,那么开发者也会有小白,所以为了方便起见,将这些系统调用接口都封装了起来,形成了各种各样方便快捷的函数,然后打包起来形成了库,那么所有的开发者在使用很多功能时就不需要自己写,而是直接调用库函数即可!那么这样做的目的就是专业的人做专业的事,提高开发效率、降低开发成本。

4. 进程

那在还没有学习进程之前,就问大家,操作系统是怎么管理进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!

在我们的计算里面存在许多的可执行程序,这些可执行程序是存储在磁盘当中的,当启动可执行程序时,这个可执行程序会加载到我们的内存中。当我们打开许多的可执行程序之后,OS该如何去管理内存中的这些可执行程序呢?

先把进程描述起来,再把进程组织起来!

4.1 基本概念

基本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体

进程 = 可执行程序 + 内核数据结构(PCB)

内核数据结构存在的意义就是方便OS对进程进行管理!

4.2 描述进程

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
  • 也被称之为进程PCB(process control block),Linux操作系统下的PCB是: task_struct

简而言之就是这个PCB中存放的是这个可执行程序的各种属性信息。

那么到这里再来看进程:

进程 = 可执行程序 + 内核数据结构(PCB)

这同时也回归到了我们的先描述,再组织,对进程的管理转化为对PCB链表节点的增删查改,这样有助于OS对进程的管理。

 所有运行在系统里的进程都以task_struct链表的形式存在内核里。
Linux中的进程PCB具体指的是:struct task_struct{}

不要认为一个进程PCB只能在一张链表里,它还可以存在其他的队列中,或者是其他的结构中:

4.3 task_struct核心字段

task_struct-PCB

  • 在Linux中描述进程的结构体叫做struct task_struct。
  • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的属性信息。

task_ struct内容分类

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息

4.4 ps ajx指令

进程(任务)对应的标识符:pid (process id) 

在Linux下查看进程可以在命令行中输入: ps ajx

我们可以测试一下我们自己写的可执行程序能不能在进程中查出来呢:

写一个简单的循环,然后再查找

#include <stdio.h>
#include <unistd.h>


int main()
{
    int cnt = 100;
    while(cnt--)
    {
        printf("我是一个进程...\n");
        sleep(1);
    }
    return 0;
}

使用make/Makefile形成可执行程序,并且运行之后使用ps查询:

ps ajx | head -1 && ps ajx | grep mycode
//        获取列属性       过滤mycode进程

当我们的mycode关闭之后再查的话可以发现该进程就不存在了:

那么这里还存在一个进程是什么呢?

因为我们使用grep进行行过滤操作,所以就启动了grep,那么gerp自然而然的就变成了一个进程会被我们查找出来。

结论:我们所有运行的指令、软件、自己写的程序最终都是进程!

为了进一步确认我们的进程是我们查找出来的进程,我们来学习一个系统调用接口:

4.5 getpid系统调用 

可以使用 man 2 getpid 对该接口进行查询:

该接口的作用就是获取当前进程的进程id

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


int main()
{
    int cnt = 100;
    while(cnt--)
    {
        pid_t id = getgid();  //获取进程pid
        printf("我是一个进程..., 我的进程id是: %d\n", id);
        sleep(1);
    }
    return 0;
}

4.6 kill指令

kill -9 pid

我们运行起来的程序可以通过ctrl + c终止,同时也可以通过kill -9 进程id 杀掉该进程:

可以看到我们每一次运行程序该进程的进程id都是不一样的,但是它的ppid都是一样,那么这个ppid是什么呢?

我们也可以查看一下它的ppid是什么:

所以在我们的命令行中,父进程是命令行解释器(bash)

 

朋友们、伙计们,美好的时光总是短暂的,我们本期的的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

stackY、

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

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

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

打赏作者

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

抵扣说明:

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

余额充值