计算机系统漫游
信息就是位+上下文
重点:
- 程序的生命周期从源程序(源文件)开始。源程序实际上就是由 0 和 1 组成的位序列。
- 一般用 ASCII 标准来表示文本字符,实际上是用一个字节的整数值来表示一种字符。
- 源文件中每个文本行都是以看不见的 '\n' 结束的。
- 只由 ASCII 字符组成的文件成为文本文件,其他都是二进制文件。.cpp 文件就是文本文件。
- 系统中的所有信息都是由一串比特(bit:位)表示的,区分不同数据对象的唯一方法就是根据上下文。
- 信息的两个要素
信息的两个要素分别是位+上下文。位表示在二进制当中每一位由值0和1组成的序列,8个位被组织成一组,称为字节。上下文可以理解为程序执行的背景环境,包含了在特定时刻程序所需的所有信息。
- 文本文件是由 ASCII 标准表示的字符组成的
- 数字0-9是由ASCII码48-57
- 大写字母A-Z是由ASCII码65-90
- 小写字母a-z是由ASCII码97-122
程序编译系统的底层原理
从源程序到目标程序要经历四个步骤:
- 源程序被预处理器处理得到修改了的源程序(文本文件,
hello.i
) - 再由编译器处理得到汇编程序(文本文件,
hello.s
) - 汇编程序由汇编器处理得到可重定位目标程序(二进制文件,
hello.o
) - 最后由链接器链接得到可执行目标程序(二进制文件,
hello
)
-
预处理阶段。预处理器(
cpp
)根据以字符#开头的命令,修改原始的C程序。比如
hello.c
中引入了#include<stdio.h>
命令告诉预处理器读取系统头文件
stdio.h
的内容,并把它直接插入程序文本中。结果就得到了另一个C程序,通常
是以.i
作为文件扩展名。 -
编译阶段。编译器(
ccl
)将文本文件hello.i
翻译成文本文件hello.s
,这一过程称之为编译。其中编译这一阶段包括词法分析、语法分析、语义分析、中间代码生成以及优化等一系列的中间操作
-
汇编阶段。汇编器(
as
)将hello.s
翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标文件——hello.o
。hello.o
文件是一个二进制文件,它包含的17个字节是函数main
的指令编码。如果我们在文本编辑器中打开hello.o
文件,将看到一堆乱码。 -
链接阶段。
hello
程序调用了printf
函数,它是每个C编译器都提供的
标准C库中的一个函数。printf
函数存在于一个名为printf.o
的单独的预编译
好了的目标文件中,而这个文件必须以某种方式合并到我们的hello.o
程序中。链
接器(ld
)就负责处理这种合并。结果就得到hello
文件,它是一个可执行目标文件
(或者简称为可执行文件),可以被加载到内存中,由系统执行。
了解编译系统如何工作是大有用处的
- 优化程序性能。现代编译器都是成熟的工具,通常可以生成很好的代码。作为程序
员,我们无须为了写出高效代码而去了解编译器的内部工作。但是,为了在C程序中
做出好的编码选择,我们确实需要了解一些机器代码以及编译器将不同的C语句转化
为机器代码的方式。比如,一个switch语句是否总是比一系列的if-else语句高效
得多?一个函数调用的开销有多大?while循环比for循环更有效吗?指针引用比数
组索引更有效吗?为什么将循环求和的结果放到一个本地变量中,会比将其放到一个
通过引用传递过来的参数中,运行起来快很多呢?为什么我们只是简单地重新排列一
下算术表达式中的括号就能让函数运行得更快?-
Switch语句 vs. If-Else语句:
- 一般来说,
switch
语句在处理多个相互排斥的条件时会比一系列的if-else
语句效率更高,因为switch
语句会使用跳转表来快速定位到匹配的分支。但是,对于较少的条件或者条件不是连续的情况下,if-else
语句也许会更加高效。
- 一般来说,
-
函数调用的开销:
- 函数调用的开销包括保存当前函数的状态、传递参数、跳转到函数体等操作。这些开销相对较小,但在频繁调用的情况下会产生累积效应。
-
While循环 vs. For循环:
while
循环和for
循环的性能基本相同。它们之间的选择通常取决于编程习惯和代码的可读性。
-
指针引用 vs. 数组索引:
- 在某些情况下,使用指针引用可能会比数组索引更高效,因为指针直接指向内存地址,而数组索引可能需要进行一些额外的计算。然而,现代编译器通常会对数组索引进行优化,使得它们的性能差异不太明显。
-
将循环求和结果放到本地变量 vs. 通过引用传递参数:
- 将循环求和结果存储在本地变量中通常会比通过引用传递参数要快,因为本地变量的访问速度更快。另外,通过引用传递参数可能会引入额外的内存访问开销,特别是如果参数是通过指针传递的话。
-
重新排列算术表达式中的括号:
- 重新排列算术表达式中的括号可能会影响编译器的优化,使得代码生成的机器指令更加高效。这种优化可能会导致更少的临时变量或更好的指令流水线利用,从而提高函数的运行速度。
-
- 理解链接时出现的错误。根据我们的经验,一些最令人困扰的程序错误往往都与链
接器操作有关,尤其是当你试图构建大型的软件系统时。比如,链接器报告说它无
法解析一个引用,这是什么意思?静态变量和全局变量的区别是什么?如果你在不
同的C文件中定义了名字相同的两个全局变量会发生什么?静态库和动态库的区别
是什么?我们在命令行上排列库的顺序有什么影响?最严重的是,为什么有些链接
错误直到运行时才会出现?-
链接器报告无法解析引用:
- 当链接器报告无法解析引用时,意味着它无法找到程序中某个符号的定义。这可能是因为该符号的定义未包含在任何被链接的目标文件或库中。
-
静态变量和全局变量的区别:
- 静态变量是在函数内部声明的变量,其作用域局限于声明它的函数内,但其生存周期会延长到整个程序运行期间。全局变量则是在函数外部声明的变量,其作用域为整个程序,生存周期也是整个程序运行期间。
-
在不同的C文件中定义相同名字的全局变量:
- 如果在不同的C文件中定义了相同名字的全局变量,编译器会认为它们是不同的变量,每个文件都会有自己的全局变量副本。在链接阶段,链接器可能会报重复符号定义的错误。
-
静态库和动态库的区别:
- 静态库是在链接时将库的代码和数据复制到可执行文件中,因此可执行文件不再依赖于库的存在。动态库则是在运行时加载到内存中,多个程序可以共享动态库,节省内存空间。
-
命令行上排列库的顺序的影响:
- 在命令行上排列库的顺序很重要,因为链接器会按照库的排列顺序搜索符号。如果某个符号在前面的库中找不到,链接器会尝试在后面的库中查找。因此,正确的库的排列顺序可以避免链接错误。
-
链接错误直到运行时才出现的原因:
- 有些链接错误,如符号未定义或重复定义,可能在链接阶段无法被检测出来,因为链接器只能看到单个目标文件或库,而无法了解整个程序的结构。这些错误可能在运行时才会显现,因为程序在执行时才会访问到特定的符号。
-
处理器读并解释储存在内存中的指令
shell
是一个命令行解释器,它输出一个提示符,等待输人一个命令行,然后执行这
个命令。如果该命令行的第一个单词不是一个内置的shell命令,那么shell就会假设这是
一个可执行文件的名字,它将加载并运行这个文件。所以在此例中,shell将加载并运行
hello程序,然后等待程序终止。hello程序在屏幕上输出它的消息,然后终止。shell
随后输出一个提示符,等待下一个输人的命令行。
系统的硬件组成
主要包括总线、I/O 设备、处理器、主存储器四个部分
总线
总线一次可以传输一个定长的字节块,称为字。64位系统即总线一次可以传输 64 位(8字节),这里一个字就是 8 字节;32位系统即总线一次可以传输 32 位(4字节),这里一个字就是 4 字节
I/O 设备
每个 I/O 设备通过一个控制器或适配器与 I/O 总线相连。
控制器是 I/O 设备本身或主板上的芯片组,适配器则是一块插在主板上的卡。
主存
主存是一个临时存储设备,在处理器执行程序时,用来存放程序和程序处理的数据,它是由一组动态随机存取内存(DRAM)组成的。从逻辑上看,存储器是一个线性的字节数组,每个字节都有唯一的地址。
处理器
概念
处理器是执行存储在主存中指令的引擎。
核心
处理器的核心是一个程序计数器(PC)。程序计数器是一个大小为一个字的存储设备,存储CPU即将执行的下一条指令的地址。
原理
- 处理器就是在不断执行程序计数器指向的指令。每执行一条,程序计数器更新一次,指向下一条指令。
- 处理器会按照指令执行模型(指令集架构)解释指令中的位并执行相应操作。
指令执行介绍
每条指令的操作是围绕主存、寄存器文件、算数/逻辑单元(ALU)进行的。
寄存器文件:单个字长,有唯一的名字。
ALU:计算新的数据和地址值。
几个简单指令的操作介绍:
- 加载:从主存复制一个字或字节到寄存器,覆盖原来内容
- 存储:从寄存器复制一个字或字节到主存,覆盖原来内容
- 操作:把两个寄存器的内容复制到 ALU,ALU 对这两个字做算术运算,并把结果存到一个寄存器中
- 跳转:从指令中抽取一个字复制到程序计数器中,覆盖原来内容。
区分处理器指令集架构和微体系架构的方法
- 指令集架构:每条机器指令的效果
- 微体系架构:处理器实际上是如何实现的
运行hello程序
流程
执行目标文件时,shell 程序将位于磁盘目标文件中的字符逐个读入寄存器,然后放到主存中。之后处理器就开始执行目标文件的机器语言指令。这些指令将“hello,world\n”
字符串中的字节从主存复制到寄存器文件,再从寄存器文件中复制到显示设备,最终显示在屏幕上。(利用直接存储器存取(DMA)可以不通过寄存器,直接将数据从磁盘到达内存。)
流程图:
高速缓存(cahe)
高速缓存(Cache)用于提高数据访问速度和性能。它是一种临时存储器,用于存储常用数据以减少对较慢主存(主内存)的访问次数。缓存通常位于处理器和主存之间,以满足处理器的高速数据访问需求。通过让高速缓存里存放可能经常访问的数据,让大部分的内存操作都在高速缓存中完成。以下是关于高速缓存的详细介绍:
-
缓存工作原理:
- 当处理器需要访问数据时,它首先检查缓存。
- 如果数据位于缓存中(命中),处理器可以快速访问它,从而提高性能。
- 如果数据不在缓存中(未命中),处理器必须从主存中加载数据,这通常需要更多的时间。
-
缓存层次结构:
- 计算机系统通常采用多级缓存层次结构,包括L1、L2、L3缓存等。
- L1缓存最接近处理器核心,速度最快但容量最小。
- L2和L3缓存通常更大,但速度略慢于L1。
-
缓存命中和未命中:
- 命中是指所需数据在缓存中可用,处理器可以快速访问它。
- 未命中是指所需数据不在缓存中,需要从主存中加载,这会引起一定的延迟。
-
替换策略:
- 当缓存已满且需要加载新数据时,缓存控制器必须决定哪些数据从缓存中删除以腾出空间。
- 常见的替换策略包括最近最少使用(LRU)、先进先出(FIFO)、随机替换等。
-
写策略:
- 缓存还可以配置为写回(write-back)或写直通(write-through)模式。
- 写回模式在缓存中修改数据,然后在稍后将其写回主存,以减少写操作的频率。
- 写直通模式会立即将写操作传递到主存,以保持一致性。
-
缓存关联性:
- 缓存可以是直接映射、组相联或全相联。
- 直接映射每个缓存行只映射到主存中的一个特定地址。
- 组相联和全相联允许一个缓存行映射到多个主存地址,提高了命中率。
-
缓存大小:
- 缓存的大小通常取决于成本、性能需求和芯片空间。
- 更大的缓存可以提高命中率,但也会增加制造成本。
-
多核处理器中的缓存:
- 在多核处理器中,每个核心通常有自己的私有缓存(L1缓存),并共享较大的缓存(L2、L3等)。
- 共享缓存用于加速核心之间的数据共享和协作。
高速缓存是计算机体系结构中的关键设计元素,它可以显著提高计算机系统的性能,减少主存访问时的延迟。不同的应用和场景可能需要不同类型和大小的缓存来优化性能。
存储设备的层次结构
存储设备组成了一个存储器层次结构,如图1-9所示。在这个层次结构中,从上至下,设备的访问速度越来越慢、容量越来越大,并且每字节的造价也越来越便宜。寄存器文件在层次结构中位于最顶部,也就是第0级或记为L0
。这里展示的是三层高速缓存L1
到L3
,占据存储器层次结构的第1层到第3层。主存在第4层,以此类推。
主要思想是上一层的存储器作为低一层的高速缓存
操作系统
操作系统可以看成是应用程序和硬件之间插入的一层软件。
操作系统基本功能:
- 防止硬件被失控的应用程序滥用
- 向应用程序提供简单一致的机制来控制复杂的低级硬件设备
操作系统所应用的三个基本的抽象概念:
- 进程:对处理器、主存和 I/O 设备的抽象表示
- 虚拟内存:对主存和磁盘的抽象表示
- 文件:对 I/O 设备的抽象表示
进程
操作系统中进程的原理
- 一个系统可以同时运行多个进程,实际上这些进程是并发运行的(并发运行:一个进程的指令和另一个进程的指令是交错执行的。)。
- 操作系统通过上下文切换来实现并发运行。上下文是跟踪进程运行所需的所有状态信息,可能存在于PC、寄存器文件、主存等地方。
- 任何时刻,单处理器只能执行一个进程的代码。
- 操作系统内核是操作系统代码常驻主存的部分,从一个进程到另一个进程的转换是由内核管理的。
- 内核不是一个独立的进程,是一系列代码和数据结构的集合。
- 当应用程序需要操作系统的某些操作时,就把控制权传递给内核,内核执行完操作后返回应用程序。
进程的详细介绍
- 定义
进程是程序的执行实例,包括代码、数据和系统资源的副本。每个进程都在操作系统内部有一个独立的表示,它运行在自己的虚拟地址空间中。
- 特征
- 独立性:每个进程都是独立的,它们互相隔离,不会相互干扰。
- 并发性:操作系统可以同时运行多个进程,实现多任务处理。
- 隔离性:进程之间的数据和资源通常是隔离的,防止相互干扰。
- 独立执行:每个进程可以独立执行,中断一个进程通常不会影响其他进程。
- 状态
进程可以处于不同的状态,包括就绪、运行、阻塞等。
-
就绪状态:进程已准备好运行,但尚未分配CPU时间。
-
运行状态:进程正在执行。
-
阻塞状态:进程在等待某些事件(如I/O操作完成)时被暂停。
以下是三种不同状态的转换关系:
- 进程控制块(PCB):
- 操作系统维护有关每个进程的信息的数据结构,称为进程控制块。
- PCB包含了进程的状态、程序计数器、寄存器值、内存指针、进程ID等信息。
- 进程调度:
- 操作系统负责决定哪个进程获得CPU时间。
- 进程调度算法确定了进程在就绪队列中的顺序。
- 进程间通信:
- 进程通常需要相互通信以共享数据或协作完成任务。
- 操作系统提供了多种进程间通信机制,如管道、消息队列、共享内存等。
- 多任务处理:
- 操作系统可以同时运行多个进程,从而实现多任务处理。
- 多任务处理可以提高系统的效率和响应速度。
- 进程的创建与终止:
- 进程可以通过操作系统的API或系统调用来创建。
- 进程可以正常退出或被强制终止。
- 进程调度策略:
- 操作系统使用不同的进程调度策略,如先来先服务(FCFS)、最短作业优先(SJF)、时间片轮转等,以确定哪个进程获得CPU时间。
- 进程同步与互斥:
- 多个进程之间的并发执行可能导致竞争条件和数据一致性问题。
- 操作系统提供了同步和互斥机制,如信号量、互斥锁,来协调进程之间的操作。
线程
线程(Thread)用于并发执行任务。线程是进程内的执行单元,一个进程可以包含多个线程,它们共享进程的内存空间和资源。以下是关于线程的详细介绍:
-
定义:
- 线程是进程内的执行单元,它代表了进程中的一个独立控制流。一个进程可以包含一个或多个线程。
-
特征:
- 轻量级:相对于进程,线程的创建和切换开销较小,因为它们共享进程的地址空间和资源。
- 共享资源:线程共享进程的内存、文件描述符等资源,使数据共享和通信更容易。
- 独立执行:每个线程可以独立执行代码,拥有自己的程序计数器和栈,但共享进程的全局数据。
-
线程状态:
- 线程可以处于不同的状态,包括就绪、运行、阻塞等,类似于进程状态。
- 就绪状态:线程已准备好运行,但尚未获得CPU时间。
- 运行状态:线程正在执行。
- 阻塞状态:线程在等待某些事件(如I/O操作完成)时被暂停。
-
线程调度:
- 操作系统负责决定哪个线程获得CPU时间。
- 线程调度算法确定了线程在就绪队列中的顺序。
-
线程间通信:
- 由于线程共享进程的内存空间,它们可以通过共享内存等机制来进行通信。
- 这种通信更快速,但也需要谨慎管理以避免竞争条件。
-
多线程应用:
- 多线程应用可以在单个进程内并发执行多个任务,提高了应用程序的性能和响应速度。
- 例如,一个多线程的Web服务器可以同时处理多个客户端请求。
-
线程的创建与销毁:
- 线程可以通过编程语言的API或库函数来创建。
- 线程可以正常终止或被强制终止。
-
线程同步与互斥:
- 多个线程共享数据时,可能导致竞争条件和数据一致性问题。
- 同步和互斥机制,如互斥锁、信号量、条件变量,用于协调线程之间的操作。
-
用户线程与内核线程:
- 用户线程是由用户级线程库管理的,而内核线程是由操作系统管理的。
- 内核线程更稳定,但用户线程更轻量。一般情况下,用户线程映射到内核线程。
虚拟内存
-
定义:
- 虚拟内存是一种计算机内存管理技术,它允许程序访问一个大于物理内存总量的地址空间。虚拟内存将物理内存和硬盘空间结合使用,允许将数据从物理内存移动到硬盘上,从而实现更大的可用内存。
-
主要特征:
- 地址空间分离:虚拟内存将程序的地址空间分为多个页面,程序可以访问这些页面,而不需要了解物理内存的详细情况。
- 分页机制:虚拟内存使用分页机制将程序的地址空间划分成固定大小的页,这些页可以在物理内存和硬盘之间交换。
- 虚拟内存页表:操作系统维护一个虚拟内存页表,用于跟踪程序的虚拟内存页与物理内存页之间的映射关系。
- 分段机制:除了分页,一些系统还使用分段机制,将程序的地址空间划分为不同的段,每个段可以有不同的大小和保护属性。
-
工作原理:
- 当程序访问一个虚拟内存地址时,操作系统检查虚拟内存页表以确定对应的物理内存位置。
- 如果所需数据位于物理内存中,访问就会直接进行。
- 如果数据不在物理内存中,操作系统将所需的虚拟内存页从硬盘加载到物理内存,并更新虚拟内存页表。
- 当物理内存不足时,操作系统可以将不常用的物理内存页交换到硬盘上,以腾出空间供其他页使用。
-
优势:
- 更大的可用内存:虚拟内存允许程序访问比物理内存更大的地址空间,从而支持运行更大的应用程序。
- 内存隔离:虚拟内存提供了进程之间的内存隔离,防止一个程序的错误影响其他程序。
- 内存保护:虚拟内存允许操作系统将不同的内存区域标记为只读、可写、可执行,从而提高安全性。
-
缺点:
- 性能开销:虚拟内存引入了额外的开销,如页表查找和页面交换,可能会对性能产生一定影响。
- 复杂性:虚拟内存的实现和管理是复杂的,需要额外的硬件支持和操作系统功能。
- 硬盘访问延迟:当虚拟内存页面需要从硬盘加载时,会引入较大的访问延迟,影响性能。
虚拟地址空间
- 定义:
- 虚拟地址空间是一个抽象的、线性的地址空间,每个进程都有自己的虚拟地址空间。
- 虚拟地址空间的大小通常远大于物理内存的大小,这使得操作系统能够为每个进程提供更多的地址空间。
- 组成部分
在linux中,每个进程看到的虚拟地址空间由以下几个部分组成(图中的地址是从下往上增大的):
- 程序代码和数据。对所有进程来说,代码都是从同一个固定地址开始,紧接着是与全局变量对应的数据区。代码和数据区都是按照可执行文件的内容初始化的。代码和数据区在进程开始运行时就被指定了大小。
- 堆(运行时堆)。运行时堆是根据 malloc 和 free 函数的调用在运行时动态地扩展和收缩的。
- 共享库。地址空间的中间部分用来存放共享库的代码和数据。如 C 标准库、数学库等都属于共享库。
- 栈(用户栈)。用户栈和堆一样,在程序执行期间可以动态的扩展和收缩,编译器用它来实现函数调用。当调用函数时,栈增长,从函数返回时,栈收缩
- 内核虚拟内存。地址从低到高,最高层的内核虚拟内存保存的是操作系统中的代码和数据,这部分每个进程都一样。
虚拟地址的映射机制
-
页表和分页机制:
- 大多数现代计算机系统使用页表来管理虚拟地址和物理地址之间的映射。页表是一个数据结构,记录了虚拟页面(通常是固定大小的页面)到物理页面的映射。
- 进程的虚拟地址空间被划分为多个页面,每个页面的大小是固定的(通常为
4KB
或4MB
)。 - 当进程访问虚拟地址时,操作系统将虚拟地址分解为虚拟页号和页内偏移,然后使用页表查找相应的物理页号。
- 如果映射存在,虚拟页号将映射到物理页号,从而实现虚拟地址到物理地址的映射。
-
页表项:
- 页表中的每个表项通常包含以下信息:
- 有效位(Valid Bit):指示该表项是否有效,即虚拟页号是否映射到物理页号。
- 物理页号(Physical Page Number):如果有效位为真,则表示虚拟页号映射到的物理页号。
- 保护位(Protection Bit):指示该页是否可以读取、写入或执行。
- 其他控制位:可能包括脏位(表示该页是否被修改过)等。
- 页表中的每个表项通常包含以下信息:
-
缺页异常:
- 如果虚拟地址对应的页表项无效(有效位为假),就会触发缺页异常(Page Fault)。
- 操作系统会捕获缺页异常,并根据需要将虚拟页从磁盘加载到物理内存中,然后更新页表以反映新的映射关系。
- 一旦缺页处理完成,进程可以继续执行。
-
TLB(Translation Lookaside Buffer):
- TLB是一个高速缓存,用于加速虚拟地址到物理地址的映射查找。
- 当进程访问虚拟地址时,TLB中存储了最近的虚拟页号到物理页号的映射。
- 如果TLB命中,可以避免访问页表,提高访问速度。
虚拟地址的映射机制允许操作系统有效地管理进程的内存,并提供内存隔离和保护。通过页表、段表、TLB等机制,操作系统可以动态地将虚拟地址映射到物理地址,允许多个进程同时运行,每个进程独享整个物理内存。
多个虚拟地址可以共享同一个物理页,即多个虚拟地址可以映射到同一个物理地址。
- 优点:
- 内存共享:多个进程可以共享相同的物理内存页,这对于共享数据和代码非常有用。例如,多个进程可以共享相同的共享库或只读数据,而不需要为每个进程单独复制这些数据。
- 提高内存利用率:多个进程可以共享相同的物理内存页,从而减少了内存的浪费。这对于具有大量相似数据或代码的进程来说特别重要。
- 更快的进程创建:当多个进程需要相同的初始化数据或代码时,可以共享这些数据而不需要每次创建新的拷贝。这减少了进程创建的时间和资源开销。
- 更快的数据传输:在进行进程间通信时,共享物理内存页可以减少数据传输的开销,因为数据不需要复制到不同的内存位置。
文件
文件就是字节序列。每个 I/O 设备,包括磁盘、键盘、显示器、网络,都可以看成是文件。在linux中,一切皆文件。文件用于存储数据、程序代码和其他信息。以下是有关操作系统文件的详细介绍:
-
文件的定义:
- 文件是一个具有唯一标识符的数据集合,它可以包含文本、二进制数据、程序代码等。
- 文件通常用于长期存储和组织数据,以供进程随时访问。
-
文件属性:
- 文件具有以下属性:
- 文件名:用于唯一标识文件的名称。
- 文件类型:表示文件的内容类型,例如文本文件、图像文件、可执行文件等。
- 文件大小:文件包含的数据的大小。
- 创建时间:文件创建的日期和时间。
- 修改时间:文件上次修改的日期和时间。
- 访问时间:文件上次被访问的日期和时间。
- 权限和所有者:文件的访问权限和拥有者信息。
- 文件具有以下属性:
-
文件系统:
- 操作系统使用文件系统来组织和管理文件。文件系统提供了文件的创建、删除、读取和写入等操作。
- 常见的文件系统包括FAT32、NTFS、EXT4、APFS等,每个文件系统具有自己的特性和优点。
-
文件路径:
- 文件路径是文件在文件系统中的位置表示,通常以目录(文件夹)层次结构的形式表示。
- 文件路径包括绝对路径(从根目录开始的完整路径)和相对路径(相对于当前工作目录的路径)。
-
文件操作:
- 操作系统提供了一组文件操作,包括创建文件、删除文件、打开文件、关闭文件、读取文件、写入文件、移动文件等。
- 这些文件操作允许进程与文件进行交互,读取和修改文件的内容。
-
文件权限:
- 操作系统通过文件权限来控制文件的访问。权限通常包括读取权限、写入权限和执行权限。
- 文件权限可以分为文件所有者、文件所属组和其他用户的权限,从而实现不同级别的访问控制。
-
文件保护:
- 操作系统使用文件保护机制来确保只有授权用户可以访问文件。这通常涉及文件权限、密码保护、加密和访问控制列表(ACL)等。
-
文件扩展名:
- 文件扩展名是文件名的一部分,用于表示文件的类型。例如,".txt"表示文本文件,".jpg"表示图像文件,".exe"表示可执行文件等。
- 尽管文件扩展名通常用于标识文件类型,但不是所有操作系统都强制执行扩展名。
-
文件类型:
- 文件可以分为不同的类型,如文本文件、二进制文件、目录文件、特殊文件等。不同类型的文件具有不同的用途和处理方式。
-
文件操作API:
- 操作系统提供了文件操作的应用程序接口(API),允许应用程序与文件系统进行交互。这些API包括open、write、read等。
文件提供了一种在不同进程之间共享信息的方式。文件系统是操作系统的一部分,负责管理和维护文件,使它们能够有效地被访问和操作。操作系统的文件管理功能对于计算机系统的正常运作和数据存储至关重要。
系统之间利用网络通信
-
从一个单独的系统而言,网络可以视为一个 I/O 设备。
-
以在一个远端服务器运行程序为例,在本地输入,在远端执行,执行结果发送回本地输出。以下是在远端运行hello程序的五个基本步骤:
当我们在telnet客户端键入“hello”字符串并敲下回车键后,客户端软件就会将这个字符串发送到telnet的服务器。telnet服务器从网络上接收到这个字符串后,会把它传递给远端shell程序。接下来,远端shell运行hello程序,并将输出行返回给telnet服务器。最后,telnet服务器通过网络把输出串转发给telnet客户端,客户端就将输出串输出到我们的本地终端上。
重要主题
Amdahl 定律
Amdahl 定律的主要观点:要加速整个系统,必须提升全系统中相当大的部分。
并发和并行
区分并发与并行:
- 并发:一个通用的概念,指一个同时具有多个活动的系统
- 并行:用并发来使系统运行得更快
并行可以在多个抽象层次上运用。从高到低有以下三个层次
1.线程级并行
传统意义上的并发执行是通过单处理器在进程间快速切换模拟出来的。
多处理器系统由一个操作系统控制多个 CPU。结构如下
L1 高速缓存被分为两个部分:一个保存最近取到的指令,一个存放数据。
超线程又称同时多线程,它允许一个 CPU 执行多个控制流。 CPU 有的硬件有多个备份,比如程序计数器和寄存器文件,而其他硬件只有一份,比如浮点算术运算单元。常规 CPU 需要约 20000 个时钟周期来切换线程,超线程 CPU 可以在单个周期的基础上切换线程,比如一个线程在等待数据装在到高速缓存,CPU 就可以去执行另一个线程。
i7 处理器每个核执行两个线程,所以是 4 核 8 线程,8 个线程都并行执行。
2. 指令级并行
每条指令从开始到结束一般需要 20 个或更多的时钟周期,通过指令级并行,可以实现每个周期 2~4 条指令的执行速率。
如果比一个周期一条指令更快,就称为超标量处理器,现在一般都是超标量。
3. 单指令、多数据并行
在最低层次上,现代处理器允许一条指令产生多个可以并行执行的操作,称为单指令、多数据并行,即 SIMD 并行。
计算机系统中抽象的重要性
指令集架构是对 CPU 硬件的抽象,使用这个抽象,CPU 看起来好像一次只执行机器代码程序的一条指令,实际上底层硬件并行地执行多条指令。
虚拟机是对整个计算机系统的抽象,包括操作系统、处理器和程序。
标签:文件,缓存,操作系统,线程,内存,进程,漫游 From: https://www.cnblogs.com/keep--fighting/p/18067882