linux系统结构

系统结构

在这里插入图片描述
在这里插入图片描述
linux系统可以分为用户空间和内核空间,其中:

  • 用户空间:包含应用程序、shell命令、各种标准库(譬如:C语言库)等。
  • 内核空间:基本可以分为三层,分别是系统调用层(SCI)、内核层、架构相关层。

系统调用层(System Call Interface)是内核空间和用户空间的接口层,提供了一系列的系统API给用户空间,便于用户使用linux的功能。譬如:文件相关的系统调用open/read/write/close。

内核层(Kernel)是linux内核空间中独立于特定的处理器体系架构的内核代码,这些代码是linux支持的所有处理器体系架构都通用的部分。

架构相关层(Architecture Dependent Kernel Code)是内核空间中与特定处理器体系架构相关的部分代码。

内核结构

linux内核主要含五个子系统:

  • 进程调度器
  • 内存管理器
  • 虚拟文件系统
  • 网络
  • 进程间通信
    在这里插入图片描述

进程调度器(Process Scheduler)

进程在不同的操作系统中有些称为process,有些称为task。操作系统中进程数据结构包含了很多元素,往往用链表连接。

进程相关的内容主要包括:虚拟地址空间,优先级,生命周期(阻塞,就绪,运行等),占有的资源(例如信号量,文件等)。

CPU在每个系统滴答(Tick)中断产生的时候检查就绪队列里面的进程(遍历链表中的进程结构体),如有符合调度算法的新进程需要切换,保存当前运行的进程的信息(包括栈信息等)后挂起当前进程,选择新的进程运行,这就是进程调度。

进程的优先级差异是CPU调度的基本依据,调度的终极目标是让高优先级的活动能够即时得到CPU的计算资源(即时响应),低优先级的任务也能公平分配到CPU资源。因为需要保存进程运行的上下文(process context)等,进程的切换本身是有成本的,调度算法在进程切换频率上也需要考虑效率。

在早期的Linux操作系统中,主要采用的是时间片轮转算法(Round-Robin),内核在就绪的进程队列中选择高优先级的进程运行,每次运行相等的时间。该算法简单直观,但仍然会导致某些低优先级的进程长时间无法得到调度。为了提高调度的公平性,在Linux 2.6.23之后,引入了称为完全公平调度器CFS(Completely Fair Scheduler)。

CPU在任何时间点只能运行一个程序,用户在使用优酷APP看视频时,同时在微信中打字聊天,优酷和微信是两个不同的程序,为什么看起来像是在同时运行?CFS的目标就是让所有的程序看起来都是以相同的速度在多个并行的CPU上运行,即nr_running 个运行的进程,每个进程以1/nr_running的速度并发执行,例如如有2个可运行的任务,那么每个以50%的CPU物理能力并发执行。

CFS引入了"虚拟运行时间"的概念,虚拟运行时间用p->se.vruntime (nanosec-unit) 表示,通过它记录和度量任务应该获得的"CPU时间"。在理想的调度情况下,任何时候所有的任务都应该有相同的p->se.vruntime值(上面提到的以相同的速度运行)。因为每个任务都是并发执行的,没有任务会超过理想状态下应该占有的CPU时间。CFS选择需要运行的任务的逻辑基于p->se.vruntime值,非常简单:它总是挑选p->se.vruntime值最小的任务运行(最少被调度到的任务)。

CFS使用了基于时间排序的红黑树来为将来任务的执行排时间线。所有的任务按p->se.vruntime关键字排序。CFS从树中选择最左边的任务执行。随着系统运行,执行过的任务会被放到树的右边,逐步地地让每个任务都有机会成为最左边的任务,从而在一个可确定的时间内获得CPU资源。

总结来说,CFS首先运行一个任务,当任务切换(或者Tick中断发生的时候)时,该任务使用的CPU时间会加到p->se.vruntime里,当p->se.vruntime的值逐渐增大到别的任务变成了红黑树最左边的任务时(同时在该任务和最左边任务间增加一个小的粒度距离,防止过度切换任务,影响性能),最左边的任务被选中执行,当前的任务被抢占。
CFS红黑树
CFS红黑树*
一般来说,调度器处理单个任务,且尽可能为每个任务提供公平的CPU时间。某些时候,可能需要将任务分组,并为每个组提供公平的CPU时间。例如,系统可以为每个用户分配平均的CPU时间后,再为每个用户的每个任务分配平均的CPU时间。

内存管理器(Memory Manager)

内存本身是一个外部存储设备,系统需要对内存区域寻址,找到对应的内存单元(memory cell),读写其中的数据。

内存区域通过指针寻址,CPU的字节长度(32bit机器,64bit机器)决定了最大的可寻址地址空间。在32位机器上最大的寻址空间是4GBtyes。在64位机器上理论上有2^64Bytes。

最大的地址空间和实际系统有多少物理内存无关,所以称为虚拟地址空间。对系统中所有的进程来说,看起来每个进程都独立占有这个地址空间,且它无法感知其它进程的内存空间。事实上操作系统让应用程序无需关注其它应用程序,看起来每个任务都是这个电脑上运行的唯一进程。

Linux将虚拟地址空间分为内核空间和用户空间。每个用户进程的虚拟空间范围从0TASK_SIZE。从TASK_SIZE2^322^64的区域保留给内核,不能被用户进程访问。TASK_SIZE可以配置,Linux系统默认配置3:1,应用程序使用3GB的空间,内核使用1GB的空间,这个划分并不依赖实际RAM的大小。在64位机器上,虚拟地址空间的范围可以非常大,但实际上只使用其中42位或47位(2^42 2^47)。
在这里插入图片描述

虚拟文件系统(Virtual File System)

Unix系统是建立在一些有见地的理念上的,一个非常重要的隐喻是:Everything is a file.
即系统几乎所有的资源都可以看成是文件。为了支持不同的本地文件系统,内核在用户进程和文件系统实现间包含了一层虚拟文件系统(Virtual File System)。大多数的内核提供的函数都能通过VFS(Virtual File System)定义的文件接口访问。例如内核子系统:字符和块设备,管道,网络Socket,交互输入输出终端等。

另外用于操作字符和块设备的设备文件是在/dev目录下的真实文件,当读写操作执行的时候,其的内容会被对应的设备驱动动态创建。
在这里插入图片描述
在虚拟文件系统中,inode用来表示文件和文件目录(对于系统来说,目录是一种特殊的文件)。inode的元素包含两类:1. Metadata用于描述文件的状态,例如读写权限。2. 用于保存文件内容的数据段。

每个inode都有一个特别的号码用于唯一识别,文件名和inode的关联建立在该编号基础上。以内核查找/usr/bin/emacs为例,讲解inodes如何组成文件系统的目录结构。从根inode开始查找(即根目录‘/’),该目录使用一个inode表示,inode的数据段没有普通的数据,只包含了根目录存的一些文件/目录项,这些项可以表示文件或其它目录,每项包含两个部分:1. 下一个数据项所在的inode编号 2. 文件或目录名

首先扫描根inode的数据区域直到找到一个名为‘usr’的项,查找子目录usr的inode。通过‘usr’ inode编号找到关联的inode。重复以上步骤,查找名为‘bin’的数据项,然后在其数据项的‘bin’对应的inode中搜索名字‘emacs’的数据项,最后返回的inode表示一个文件而不是一个目录。最后一个inode的文件内容不同于之前,前三个每个都表示了一个目录,包含了它的子目录和文件清单,和emacs文件关联的inode在它的数据段保存了文件的实际内容。

尽管在VFS查找某个文件的步骤和上面的描述一样,但细节上还是有些差别。例如因为频繁打开文件是一个很慢的操作,引入缓存加速查找。
在这里插入图片描述

网络

Linux的网络子系统为互联网的发展提供了坚实的基础。网络模型基于ISO的OSI模型,如下图右半部分。但在具体应用中,往往会把相应层级结合以简化模型,下图左半部分为Linux运用的TCP/IP参考模型。
在这里插入图片描述
linux基于TCP/IP分层模型提供了各种网络协议栈和管理网络设备的能力。

进程间通信(Interprocess Communication)

linux进程具有独立的地址空间,互相隔离,导致进程间无法直接通信。但是在中大型项目中多个进程协同工作很常见,则进程间通信就变得尤为重要,所以linux提供了四种进程间通信(IPC)的方式来达到通信的目的,分别是:

  • 管道
  • 共享内存
  • 消息队列
  • 信号量

管道(Pipe)

特点:半双工通信。
作用:实现进程间数据传输。
本质:内核中开辟一块内存,多个进程都访问这个内存来实现通信。
分类

  • 匿名(无名)管道:内核中开辟的这块缓冲区,没有标识符,无法被其他进程找到(只能用于具有亲缘关系的进程间通信)。
  • 命名(有名)管道:内核中开辟的这块缓冲区,有标识符,能被其他进程找到(可用于同一主机上任意进程间通信)。

匿名管道

一个进程通过系统调用在内核中创建了一个匿名管道,为了能让用户操控这个管道,因此返回了文件描述符作为这个管道的操作句柄。其他进程因为没有这个管道标识符,所以无法通信。
但是,如果这个创建管道的进程创建了一个子进程,这时候子进程复制了父进程(文件描述信息表),所以子进程相当于也有文件描述符可以操作该管道。
在这里插入图片描述

命名管道

一个进程创建一个命名管道,这个命名管道会在文件系统中创建出一个管道文件(可以看得到的,实际上就是管道的名字),多个进程通过打开同一个管道文件,访问内核中同一个缓冲区实现通信。
在这里插入图片描述

命名管道文件只是一个文件,是为了让进程找到同一个缓冲区。

共享内存(Share Memory)

特点

  • 所有进程间通信方式中最快的一种。因为通过虚拟地址直接访问内存,相较于其他方式少了两次用户空间与内核空间之间的数据拷贝。
  • 共享内存的生命周期随内核,在不人为删除的情况, 所有映射进程退出也不会释放共享内存。

本质:开辟一块物理内存,需要进行通信的进程将这块物理内存映射到自己的虚拟地址空间中,直接使用自己的用户空间地址访问。

  • 共享内存是一种覆盖式操作.
  • 共享内存的操作需要考虑安全问题(没有互斥同步关系)

操作流程

  1. 创建或打开共享内存
  2. 将共享内存映射到虚拟地址空间
  3. 内存操作(memcpy,printf)
  4. 解除映射关系
  5. 删除共享内存(共享内存不会被立即删除,而是等到共享内存的映射连接数为0时才会删除)

消息队列

特点:

  • 消息队列是消息的链表,存放于内存中,内核维护消息队列。
  • 消息队列中的消息是有类型的。
  • 消息队列中的消息是有格式的。
  • 消息队列可实现消息随机查询,并且不一定要遵循先进先出的顺序,而是每个进程可以按照感兴趣的类型进行读取。
  • 与管道相同,读出数据后,消息队列对应数据会被删除。
  • 每个管道都有消息队列标识符,在整个系统中是唯一的。
  • 消息队列允许一个或者多个进程向它写入或者读取数据。
  • 内核重启或者人为删除才会删除消息队列,否则会一直存在于系统中。

详细内容参考《进程间通信之消息队列

信号量

信号量本质是一个数据操作锁,本身并不可以进行数据的通信。而是通过其他资源进行进程间的通信,本身是一种外部标识符。为了防止多个线程同时访问同一个临界资源导致的一系列问题,使得在同一时刻只有一个线程访问代码的临界资源。信号量就是提供了这种机制,让一个临界区同一时刻只有一个线程在访问。
工作原理
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于0,就给他减1;如果值等于0,就挂起该进程的执行。
V(sv):如果有其他进程因等待sv而被挂起,就让他恢复运行,如果没有进程因等待sv而挂起,就给他加1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值