当前位置: 智迪文档网 > 范文大全 > 公文范文 >

2023年操作系统基础知识大全11篇

| 来源:网友投稿

操作系统基础知识大全第1篇计算机操作系统是基础软件,分为闭源和开源两类。广义的操作系统包括:计算机(PC、工作站、服务器)系统、移动端系统(例如鸿蒙)、嵌入式系统等。本文只涉及计算机操作系统。计算机操下面是小编为大家整理的操作系统基础知识大全11篇,供大家参考。

操作系统基础知识大全11篇

操作系统基础知识大全 第1篇

计算机操作系统是基础软件,分为闭源和开源两类。

广义的操作系统包括:计算机(PC、工作站、服务器)系统、移动端系统(例如鸿蒙)、嵌入式系统 等。本文只涉及计算机操作系统。

计算机操作系统的功能角色:作为用户和计算机硬件资源之间的交互,管理调度硬件资源,为应用 软件提供运行环境。操作系统属于基础软件,是系统级程序的汇集,为用户屏蔽底层硬件复杂度, 并提供编程接口和操作入口。操作系统控制处理器(CPU)调度系统资源,控制应用程序执行的时机, 决定各个程序分配的处理器时间(CPU time)。操作系统需要兼容底层硬件和应用软件,才能实现计算机的功能。

根据核心代码是否向开放,操作系统可划分为两类:开源系统、闭源系统。

闭源操作系统:代码不开放,以微软 Windows 系统为代表

微软公司内部的研发团队开发 Windows 操作系统,并开发配套的应用软件,比如 Office。在生态 建设方面,Intel 和 Windows 长期合作形成 Wintel 体系,在 PC 端市占率全球领先

Windows 系统的访问分为 User mode(用户模式)和 Kernel mode(内核模式)。用户级的应用程序在 用户模式中运行,而系统级的程序在内核模式中运行。内核模式允许访问所有的系统内存和 CPU 指令。Windows 系统从最早期的 16 位、32 位到现在流行的 64 位,系统版本从最初的 Windows 到 Windows 95、Windows 98、Windows 20XX、Windows 20XX、Windows __P、Windows Vista、Windows 7、Windows 8、Windows 、Windows 10 和 Windows Server 服务器企业级 操作系统,不断持续更新。

Windows 系统最大的优势在于图形界面,使得普通用户操作起来非常便利。相比大部分 Linu__ 系 统,windows 的常用软件安装和系统设置不需要以命令行的方式去输入系统指令,只需要点击“按 钮”即可完成。如今,绝大多数常见软件、专用软件和底层硬件都支持 Windows 操作系统,形成 了 Window 强大的生态整体。

开源操作系统:代码免费开放,以 Linu__ 操作系统为代表

Linu__ kernel(内核)由 Linus Torvalds 在 1991 年发布,代码免费公开,由全球开发者共同贡献, 已成为影响最广泛的开源软件项目。以 Linu__ 内核为基础,不同的开发团体(开源社区、企业、个 人等)对内核代码进行一定的修改和补充,加入 GUI(图形界面)、应用等部分,形成了相应的 Linu__ 操作系统发行版。

Linu__ 系统版本之间存在衍生关系,由此形成 RedHat、Slackware、Debian 等几大家族,各家族 内部又衍生出一些著名版本,如 Ubuntu、SUSE、CentOS、Red Hat Enterprise Linu__、Fedora 等。

Linu__ kernel 是开源项目,由全球范围的开发者(企业、团体、独立开发者)共同贡献源代码。Linu__ 的官方组织是 Linu__ 基金会,作为非盈利的联盟,协调和推动 Linu__ 系统的发展,以及宣传、保护 和规范 Linu__。Linu__ 基金会由开源码发展实验室(Open Source Development Labs,OSDL)与自 由标准组织(Free Standards Group ,FSG) 于 20XX 年联合成立。

开源社区是 Linu__ 系统的创新源泉和主要的开发场所。Linu__ 操作系统发行版分为社区版本和商 业版本。社区版本数量较多,其开发和维护的主体是开源社区。少数的商业版本(比如红帽企业版) 则是在社区版本的基础上,进一步优化而来。整体来看,无论是否涉及商业活动,开源社区是 Linu__ 发行版的创新来源和主要的开发场所。而成熟的开源社区通常由相应的开源基金会(或者项目委员 会)进行管理。开源基金会为开发社区制定了规则,进行资源管理,负责可能的商务对接,以及保 护社区的健康运转。社区的开源基金会(委员会)一般由开源贡献方进行赞助和决策支持。

许多开源社区背后都有一个主导企业,为社区提供资金和研究支撑,甚至直接委派员工参与开源 项目。例如,Fedora 社区的核心开发者中 1/3 是红帽的正式雇员。通过资助和维护开源社区的方 式,企业可以发挥研究力量的“杠杆”作用,通过向社区输入自有的研究资源,吸引更多的外部贡 献者参与进来,扩大创意来源;另一方面,开源社区版本也成为企业扩大技术影响力的重要途径。

Linu__ 操作系统由 4 部分组成:kernel、shell、文件系统、应用程序。Kernel(内核)是操作系统的 核心,不同于 windows 的内核,Linu__ 的内核不仅实现了进程调度、内存管理、中断处理、异常陷 阱处理,而且还实现了进程管理、进程通信机制、虚拟内存管理、文件系统驱动和 USB、网络、声 音等各类设备驱动子系统,决定了整个系统的性能和稳定性。而 shell 是系统的用户界面,提供用 户与内核交互的接口,接收用户输入的命令并送入内核去执行。

Linu__ 操作系统主要的优势领域是服务器和嵌入式。据 Linu__ 基金会统计,全球 90%的公有云平 台采用了 Linu__ 系统,99%的超算和 62%的嵌入式设备也都是基于 Linu__。亚马逊 AWS、微软 Azure、微软 Azure、谷歌云平台和阿里云等主流云服务商,都提供了 Linu__ 系统方案。全球公有 云平台运行的所有应用,超过 54%是运行在 Linu__ 虚拟机上。甚至微软 Azure 的近 30%的虚拟机 也是基于 Linu__。根据 IDC 在 20XX 年的统计数据,全球服务器操作系统使用份额(免费+付费)中, 68%是 Linu__ 服务器操作系统。

Linu__ 操作系统在服务器领域的普及,主要由于 3 个方面:

1)创新方面,集思广益。全球开发者对 Linu__ 内核保持了持续的更新,提供了充足的创新动力。据 GitStats 分析结果,截至 20XX 年 9 月,已有超过 19000 名开发者为 Linu__ 内核贡献了代码, 这些开发者遍布全球范围超过1500个组织/企业。广泛分布的开发者,从不同视角不同方面对Linu__ 内核的补充,使得 Linu__ 系统得以快速适应服务器领域的变化。

2)系统代码可以修改和自定义,用户可调用计算机资源的自由度极高。Linu__ 操作系统的使用者 可以轻松查看系统代码,可以自由修改代码来修补常见的问题,也可以开发自己的程序并添加入 Linu__ 操作系统中。相比 Windows 等闭源系统,Linu__ 支持了使用者对于计算机资源极大的使用自 由度,支持专业用户去构建和自定义服务器,由此获得了互联网公司、云计算公司的青睐。

3)运行效率高,运维成本低。Linu__ 系统在服务器上面的运行效率较高,相对比较轻量化,除非硬 件资源分配出现问题,不易出现系统卡死状况。而且 Linu__ 系统天然地支持虚拟化。因此,在服务 器集群上,Linu__ 系统的运维成本较低。

4)安全。Linu__ 从发展根源上就是针对多用户系统设计的,系统管理员和 root 用户具有系统管理 权限。Linu__ 面向全球开发者开源,系统文件都是文档,在全球开发者多次的筛查和更新中,基本 排除了“后门植入”的可能。实际应用中,普通不成熟的 Linu__ 操作系统确实可能存在安全问题, 也是和系统的文档属性有关。例如,用户 root 权限和 sudo 指令可在有意或无意间修改 Linu__ 系 统文档,可能会对其他用户或整个系统造成不利影响。因此,成熟的 Linu__ 操作系统解决方案,有 必要对这类属性进行设计方面的防范,去进行适当的权限屏蔽。而这些安全属性的设计,本质上并 不存在难以解决的障碍。

操作系统基础知识大全 第2篇

通常在计算机硬件上配置的OS,目标有:

方便

有效

可扩充

开放

为系统软件,所以是一种软件接口。

用户使用OS的方式

(1)命令方式:联机命令,直接操作OS

(2)系统调用:OS提供系统调用

(3)图形、窗口:GUI界面

计算机当中的资源:

硬件和软件资源。归纳起来可将资源分为四类:处理器、存储器、 I/O设备以及信息(数据和程序)。

OS的主要功能也正是针对这四类资源进行有效的管理,即:

处理机管理, 用于分配和控制处理机;

存储器管理,主要负责内存的分配与回收;

I/O设备管理,负责I/O设备的分配与操纵;

文件管理,负责文件的存取、共享和保护。

扩充机器

通常把覆盖了软件的机器称为扩充机器或虚机器。如果我们又在第一层软件上再覆盖上一层文件管理软件,则用户可利用该软件提供的文件存取命令,来进行文件的存取。此时,用户所看到的是台功能更强的虚机器。如果我们又在文件管理软件上再覆盖一层面向用户的窗口软件,则用户便可在窗口环境下方便地使用计算机,形成一台功能更强的虚机器。

操作系统的发展过程

人工操作方式

脱机输入/输出(Off-Line I/O)方式

单道批处理系统(Simple Batch Processing System)

多道批处理系统(Multiprogrammed Batch Processing System)

在该系统中, 用户所提交的作业都先存放在外存上并排成一个队列,称为“后备队列”;然后,由作业调度程序按一定的算法从后备队列中选择若干个作业调入内存,使它们共享CPU和系统中的各种资源。

如果允许在内存中装入多道程序, 并允许它们并发执行,则无疑会大大提高内存和I/O设备的利用率。

多道批处理系统需要解决的问题

(1)处理机管理问题。

(2) 内存管理问题。

(3) I/O设备管理问题。

(4) 文件管理问题。

(5) 作业管理问题。

分时系统(Time-Sharing System)

为实现分时系统,其中,最关键的问题是如何使用户能与自己的作业进行交互,即当用户在自己的终端上键入命令时, 系统应能及时接收并及时处理该命令,再将结果返回给用户。此后, 用户可继续键入下一条命令,此即人—机交互。应强调指出,即使有多个用户同时通过自己的键盘键入命令,系统也应能全部地及时接收并处理。

实时系统

所谓“实时”,是表示“及时”,而实时系统(Real-Time System)是指系统能及时(或即时)响应外部事件的请求,在规定的时间内完成对该事件的处理,并控制所有实时任务协调一致地运行。

(1) 硬实时任务(hard real-time task)。系统必须满足任务对截止时间的要求,否则可能出现难以预测的结果。

(2) 软实时任务(Soft real-time task)。它也联系着一个截止时间, 但并不严格,若偶尔错过了任务的截止时间, 对系统产生的影响也不会太大。

操作系统的基本特性

并发

并行性和并发性是既相似又有区别的两个概念,并行性是指两个或多个事件在同一时刻发生;而并发性是指两个或多个事件在同一时间间隔内发生。在多道程序环境下,并发性是指在一段时间内,宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可同时执行。

共享(Sharing)

在操作系统环境下,所谓共享是指系统中的资源可供内存中多个并发执行的进程(线程)共同使用。由于资源属性的不同,进程对资源共享的方式也不同,目前主要有以下两种资源共享方式。

互斥共享方式

系统中的某些资源,如打印机、磁带机,虽然它们可以提供给多个进程(线程)使用,但为使所打印或记录的结果不致造成混淆,应规定在一段时间内只允许一个进程(线程)访问该资源。为此,当一个进程A要访问某资源时,必须先提出请求, 如果此时该资源空闲,系统便可将之分配给请求进程A使用, 此后若再有其它进程也要访问该资源时(只要A未用完)则必须等待。仅当A进程访问完并释放该资源后, 才允许另一进程对该资源进行访问。我们把这种资源共享方式称为互斥式共享,而把在一段时间内只允许一个进程访问的资源称为临界资源或独占资源。计算机系统中的大多数物理设备,以及某些软件中所用的栈、变量和表格,都属于临界资源,它们要求被互斥地共享。

同时访问方式

系统中还有另一类资源,允许在一段时间内由多个进程“同时”对它们进行访问。这里所谓的“同时”往往是宏观上的,而在微观上,这些进程可能是交替地对该资源进行访问。典型的可供多个进程“同时”访问的资源是磁盘设备,一些用重入码编写的文件,也可以被“同时”共享,即若干个用户同时访问该文件。

并发和共享是操作系统的两个最基本的特征,它们又是互为存在的条件。一方面,资源共享是以程序(进程)的并发执行为条件的,若系统不允许程序并发执行,自然不存在资源共享问题;另一方面,若系统不能对资源共享实施有效管理, 协调好诸进程对共享资源的访问,也必然影响到程序并发执行的程度,甚至根本无法并发执行。

虚拟(Virtual)

操作系统中的所谓“虚拟”,是指通过某种技术把一个物理实体变为若干个逻辑上的对应物。物理实体(前者)是实的, 即实际存在的;而后者是虚的,是用户感觉上的东西。相应地,用于实现虚拟的技术,称为虚拟技术。在OS中利用了多种虚拟技术,分别用来实现虚拟处理机、虚拟内存、 虚拟外部设备和虚拟信道等。

在虚拟处理机技术中,是通过多道程序设计技术,让多道程序并发执行的方法,来分时使用一台处理机的。此时, 虽然只有一台处理机,但它能同时为多个用户服务,使每个终端用户都认为是有一个CPU在专门为他服务。亦即, 利用多道程序设计技术,把一台物理上的CPU虚拟为多台逻辑上的CPU,也称为虚拟处理机,我们把用户所感觉到的CPU称为虚拟处理器。

异步性(Asynchronism)

在多道程序环境下,允许多个进程并发执行, 但只有进程在获得所需的资源后方能执行。在单处理机环境下,由于系统中只有一个处理机,因而每次只允许一个进程执行,其余进程只能等待。当正在执行的进程提出某种资源要求时,如打印请求,而此时打印机正在为其它某进程打印,由于打印机属于临界资源,因此正在执行的进程必须等待,且放弃处理机,直到打印机空闲,并再次把处理机分配给该进程时,该进程方能继续执行。可见,由于资源等因素的限制,使进程的执行通常都不是“一气呵成”,而是以“停停走走”的方式运行。

操作系统的主要功能

处理机管理功能

进程控制

在传统的多道程序环境下,要使作业运行,必须先为它创建一个或几个进程,并为之分配必要的资源。当进程运行结束时,立即撤消该进程,以便能及时回收该进程所占用的各类资源。进程控制的主要功能是为作业创建进程、撤消已结束的进程,以及控制进程在运行过程中的状态转换。在现代OS中,进程控制还应具有为一个进程创建若干个线程的功能和撤消(终止)已完成任务的线程的功能。

进程同步

为使多个进程能有条不紊地运行,系统中必须设置进程同步机制。进程同步的主要任务是为多个进程(含线程)的运行进行协调。有两种协调方式:① 进程互斥方式, 这是指诸进程(线程)在对临界资源进行访问时, 应采用互斥方式;② 进程同步方式,指在相互合作去完成共同任务的诸进程(线程)间,由同步机构对它们的执行次序加以协调。

为了实现进程同步,系统中必须设置进程同步机制。最简单的用于实现进程互斥的机制,是为每一个临界资源配置一把锁W,当锁打开时,进程(线程)可以对该临界资源进行访问;而当锁关上时,则禁止进程(线程)访问该临界资源。

进程通信

在多道程序环境下,为了加速应用程序的运行,应在系统中建立多个进程,并且再为一个进程建立若干个线程,由这些进程(线程)相互合作去完成一个共同的任务。而在这些进程(线程)之间,又往往需要交换信息。例如,有三个相互合作的进程, 它们是输入进程、计算进程和打印进程。输入进程负责将所输入的数据传送给计算进程;计算进程利用输入数据进行计算, 并把计算结果传送给打印进程;最后,由打印进程把计算结果打印出来。进程通信的任务就是用来实现在相互合作的进程之间的信息交换。?

当相互合作的进程(线程)处于同一计算机系统时,通常在它们之前是采用直接通信方式,即由源进程利用发送命令直接将消息(message)挂到目标进程的消息队列上,以后由目标进程利用接收命令从其消息队列中取出消息。

调度

在后备队列上等待的每个作业,通常都要经过调度才能执行。在传统的操作系统中,包括作业调度和进程调度两步。作业调度的基本任务,是从后备队列中按照一定的算法,选择出若干个作业,为它们分配其必需的资源(首先是分配内存)。在将它们调入内存后,便分别为它们建立进程,使它们都成为可能获得处理机的就绪进程,并按照一定的算法将它们插入就绪队列。而进程调度的任务,则是从进程的就绪队列中选出一新进程,把处理机分配给它,并为它设置运行现场, 使进程投入执行。值得提出的是,在多线程OS中,通常是把线程作为独立运行和分配处理机的基本单位,为此,须把就绪线程排成一个队列,每次调度时,是从就绪线程队列中选出一个线程,把处理机分配给它。

存储器管理功能

内存分配

OS在实现内存分配时,可采取静态和动态两种方式。在静态分配方式中,每个作业的内存空间是在作业装入时确定的;在作业装入后的整个运行期间, 不允许该作业再申请新的内存空间,也不允许作业在内存中“移动”;在动态分配方式中,每个作业所要求的基本内存空间, 也是在装入时确定的,但允许作业在运行过程中,继续申请新的附加内存空间,以适应程序和数据的动态增涨,也允许作业在内存中“移动”。

为了实现内存分配,在内存分配的机制中应具有这样的结构和功能:

① 内存分配数据结构, 该结构用于记录内存空间的使用情况, 作为内存分配的依据;

② 内存分配功能,系统按照一定的内存分配算法, 为用户程序分配内存空间;

③ 内存回收功能,系统对于用户不再需要的内存,通过用户的释放请求,去完成系统的回收功能。

内存保护

内存保护的主要任务,是确保每道用户程序都只在自己的内存空间内运行,彼此互不干扰。

为了确保每道程序都只在自己的内存区中运行,必须设置内存保护机制。一种比较简单的内存保护机制,是设置两个界限寄存器,分别用于存放正在执行程序的上界和下界。系统须对每条指令所要访问的地址进行检查,如果发生越界,便发出越界中断请求,以停止该程序的执行。如果这种检查完全用软件实现,则每执行一条指令,便须增加若干条指令去进行越界检查,这将显著降低程序的运行速度。因此,越界检查都由硬件实现。当然, 对发生越界后的处理, 还须与软件配合来完成。

地址映射

一个应用程序(源程序)经编译后,通常会形成若干个目标程序;这些目标程序再经过链接便形成了可装入程序。这些程序的地址都是从“0”开始的,程序中的其它地址都是相对于起始地址计算的;由这些地址所形成的地址范围称为“地址空间”, 其中的地址称为“逻辑地址”或“相对地址”。此外,由内存中的一系列单元所限定的地址范围称为“内存空间”, 其中的地址称为“物理地址”。

在多道程序环境下,每道程序不可能都从“0”地址开始装入(内存), 这就致使地址空间内的逻辑地址和内存空间中的物理地址不相一致。使程序能正确运行,存储器管理必须提供地址映射功能,以将地址空间中的逻辑地址转换为内存空间中与之对应的物理地址。该功能应在硬件的支持下完成。

内存扩充

存储器管理中的内存扩充任务,并非是去扩大物理内存的容量,而是借助于虚拟存储技术,从逻辑上去扩充内存容量,使用户所感觉到的内存容量比实际内存容量大得多;或者是让更多的用户程序能并发运行。这样,既满足了用户的需要,改善了系统的性能,又基本上不增加硬件投资。为了能在逻辑上扩充内存,系统必须具有内存扩充机制, 用于实现下述各功能:

(1) 请求调入功能。

(2) 置换功能。

设备管理功能

设备管理用于管理计算机系统中所有的外围设备, 而设备管理的主要任务是,完成用户进程提出的I/O请求;为用户进程分配其所需的I/O设备;提高CPU和I/O设备的利用率;提高I/O速度;方便用户使用I/O设备。为实现上述任务,设备管理应具有缓冲管理、设备分配和设备处理,以及虚拟设备等功能。

缓冲管理

CPU运行的高速性和I/O低速性间的矛盾自计算机诞生时起便已存在。而随着CPU速度迅速、大幅度的提高,使得此矛盾更为突出,严重降低了CPU的利用率。如果在I/O设备和CPU之间引入缓冲,则可有效地缓和CPU和I/O设备速度不匹配的矛盾,提高CPU的利用率,进而提高系统吞吐量。因此,在现代计算机系统中, 都毫无例外地在内存中设置了缓冲区,而且还可通过增加缓冲区容量的方法,来改善系统的性能。

最常见的缓冲区机制有单缓冲机制、能实现双向同时传送数据的双缓冲机制,以及能供多个设备同时使用的公用缓冲池机制。

设备分配

设备分配的基本任务,是根据用户进程的I/O请求、系统的现有资源情况以及按照某种设备分配策略,为之分配其所需的设备。如果在I/O设备和CPU之间,还存在着设备控制器和I/O通道时,还须为分配出去的设备分配相应的控制器和通道。

为了实现设备分配,系统中应设置设备控制表、控制器控制表等数据结构,用于记录设备及控制器的标识符和状态。据这些表格可以了解指定设备当前是否可用,是否忙碌,以供进行设备分配时参考。在进行设备分配时,应针对不同的设备类型而采用不同的设备分配方式。对于独占设备(临界资源)的分配,还应考虑到该设备被分配出去后,系统是否安全。设备使用完后,还应立即由系统回收。

设备处理

设备处理程序又称为设备驱动程序。其基本任务是用于实现CPU和设备控制器之间的通信,即由CPU向设备控制器发出I/O命令,要求它完成指定的I/O操作;反之由CPU接收从控制器发来的中断请求,并给予迅速的响应和相应的处理。

处理过程是:设备处理程序首先检查I/O请求的合法性,了解设备状态是否是空闲的,了解有关的传递参数及设置设备的工作方式。然后,便向设备控制器发出I/O命令,启动I/O设备去完成指定的I/O操作。设备驱动程序还应能及时响应由控制器发来的中断请求,并根据该中断请求的类型,调用相应的中断处理程序进行处理。对于设置了通道的计算机系统, 设备处理程序还应能根据用户的I/O请求,自动地构成通道程序。

文件管理功能

文件存储空间的管理

由文件系统对诸多文件及文件的存储空间,实施统一的管理。其主要任务是为每个文件分配必要的外存空间,提高外存的利用率,并能有助于提高文件系统的运行速度。

为此,系统应设置相应的数据结构,用于记录文件存储空间的使用情况,以供分配存储空间时参考;系统还应具有对存储空间进行分配和回收的功能。为了提高存储空间的利用率,对存储空间的分配,通常是采用离散分配方式,以减少外存零头,并以盘块为基本分配单位。盘块的大小通常为512 B~8 KB。

目录管理

为了使用户能方便地在外存上找到自己所需的文件,通常由系统为每个文件建立一个目录项。目录项包括文件名、文件属性、文件在磁盘上的物理位置等。由若干个目录项又可构成一个目录文件。目录管理的主要任务, 是为每个文件建立其目录项,并对众多的目录项加以有效的组织,以实现方便的按名存取。即用户只须提供文件名, 即可对该文件进行存取。其次,目录管理还应能实现文件共享,这样,只须在外存上保留一份该共享文件的副本。此外,还应能提供快速的目录查询手段,以提高对文件的检索速度。

文件的读/写管理和保护

(1) 文件的读/写管理。该功能是根据用户的请求,从外存中读取数据;或将数据写入外存。在进行文件读(写)时,系统先根据用户给出的文件名,去检索文件目录,从中获得文件在外存中的位置。然后,利用文件读(写)指针,对文件进行读(写)。一旦读(写)完成,便修改读(写)指针,为下一次读(写)做好准备。由于读和写操作不会同时进行,故可合用一个读/写指针。

(2) 文件保护。① 防止未经核准的用户存取文件;② 防止冒名顶替存取文件;③ 防止以不正确的方式使用文件。

用户接口

命令接口

(1) 联机用户接口。这是为联机用户提供的,它由一组键盘操作命令及命令解释程序所组成。当用户在终端或控制台上每键入一条命令后,系统便立即转入命令解释程序,对该命令加以解释并执行该命令。在完成指定功能后,控制又返回到终端或控制台上,等待用户键入下一条命令。这样,用户可通过先后键入不同命令的方式,来实现对作业的控制,直至作业完成。

(2) 脱机用户接口。

程序接口

该接口是为用户程序在执行中访问系统资源而设置的,是用户程序取得操作系统服务的惟一途径。它是由一组系统调用组成,每一个系统调用都是一个能完成特定功能的子程序,每当应用程序要求OS提供某种服务(功能)时,便调用具有相应功能的系统调用。早期的系统调用都是用汇编语言提供的,只有在用汇编语言书写的程序中,才能直接使用系统调用;但在高级语言以及C语言中,往往提供了与各系统调用一一对应的库函数,这样,应用程序便可通过调用对应的库函数来使用系统调用。但在近几年所推出的操作系统中,如UNI__、OS/2版本中,其系统调用本身已经采用C语言编写,并以函数形式提供,故在用C语言编制的程序中, 可直接使用系统调用。

图形接口

操作系统的结构设计

把微内核的OS结构称为现代OS结构。

无结构操作系统

模块化OS结构

分层式OS结构

微内核OS结构

客户/服务器模式(Client-Server Model)

面向对象的程序设计技术(Object-Orientated Programming)

1) 面向对象技术的基本概念

面向对象技术是20世纪80年代初提出并很快流行起来的。该技术是基于“抽象”和“隐蔽”原则来控制大型软件的复杂度的。所谓对象,是指在现实世界中具有相同属性、服从相同规则的一系列事物的抽象,而把其中的具体事物称为对象的实例。OS中的各类实体如进程、线程、消息、存储器等,都使用了对象这一概念,相应地,便有进程对象线程对象、 存储器对象等。

2) 面向对象技术的优点

(1) 可修改性和可扩充性。由于隐蔽了表示实体的数据和操作,因而可以改变对象的表示而不会影响其它部分, 从而可以方便地改变老的对象和增加新的对象。

(2) 继承性。继承性是面向对象技术所具有的重要特性。继承性是指子对象可以继承父对象的属性,这样,在创建一个新的对象时, 便可减少大量的时空开销。

(3) 正确性和可靠性。由于对象是构成操作系统的基本单元,可以独立地对它进行测试,这样,比较易于保证其正确性和可靠性,从而比较容易保证整个系统的正确性和可靠性。

微内核技术

所谓微内核技术,是指精心设计的、能实现现代OS核心功能的小型内核,它与一般的OS(程序)不同, 它更小更精炼,它不仅运行在核心态,而且开机后常驻内存, 它不会因内存紧张而被换出内存。微内核并非是一个完整的OS, 而只是为构建通用OS提供一个重要基础。由于在微内核OS结构中,通常都采用了客户/服务器模式,因此OS的大部分功能和服务,都是由若干服务器来提供的, 如文件服务器、作业服务器和网络服务器等。

2) 微内核的基本功能

微内核所提供的功能,通常都是一些最基本的功能,如进程管理、存储器管理、进程间通信、 低级I/O功能。

(1) 进程管理。

(2) 存储器管理。

(3) 进程通信管理。

(4) I/O设备管理。

操作系统基础知识大全 第3篇

操作系统:用于管理和控制计算机所有的硬件和软件资源的一组程序。它是最底层的系统软件,是对硬件系统功能的首次扩充,也是其它系统软件和应用软件能够在计算机上运行的基础。

1) DOS

早期的PC操作系统

单用户单任务命令行界面操作系统

从版开始成为支持多任务的操作系统。

2) Windows 图形用户界面

3) Uni__分时操作系统,主要用于服务器/客户机体系

4) Linu__由UNI__发展而来,源代码开放

5) Mac OS较好的图形处理能力,主要用在桌面出版和多媒体应用等领域。用在苹果公司的Power Macintosh机及Macintosh一族计算机上,与Windows缺乏较好的兼容性

6) Novell Netware 基于文件服务和目录服务的网络操作系统,用于构建局域网。

操作系统分类

Windows是Microsoft公司开发的图形化界面的操作系统。

·基本概念:

图标、任务栏、标题栏、菜单栏、滚动条、工具栏、对话框、开始菜单……

·基本操作

(1)鼠标单击、双击、拖动,左键、右键功能;

(2)窗口操作:最大(小)化、大小调整、拖动、关闭、排列、切换;

(3)菜单操作激活、选择;

★命令项的约定—— 正常显示和灰色显示;

命令后带“…”:执行命令则弹出对话框;

带快捷键:某些菜单命令的后面标有对应的键盘命令,称为该命令的快捷键或热键;

选中标志:某些命令选项的左侧有用打勾表示的选中标志,说明此命令功能正在起作用;

命令后带“?”:级联:此命令后会有下一级的子命令菜单弹出供用户作进一步选择;

★快捷菜单——当鼠标位于某个对象上,单击鼠标右键,可打开有关对象的快捷菜单;

(4)剪贴板:复制(Ctrl-C)、粘贴(Ctrl-V)、剪切(Ctrl-__)

复制屏幕图像:可将当前屏幕图形以BMP格式传送到剪贴板……

(5)其它:查找、运行、切换Windows、进入DOS环境、文件夹选项

输入法切换,中、英文切换,半角/全角切换

软键盘:是在屏幕上显示的一个键盘图形,用户可用鼠标点击其中某个键以替代实际的按键;

·各种文件的后缀名:

bat、com、e__e、sys、tmp、zip、……

doc、__ls、t__t、htm、……

bmp、gif、jpg、psd、……

wav、avi、mp3、swf……

由美国Microsoft公司发行的DOS称为MS-DOS,主要由、、 三个基本文件和几十个内、外部命令文件组成。

__ 主要命令:
· DIR——显示磁盘文件目录· CD——改变当前目录· MD——建立目录· RD——删除目录 · DATE——显示和设置系统日期 内部命令 · TIME——显示和设置系统时间 · COPY——复制文件· DEL——删除文件· REN——文件重命名· TYPE——显示文本文件内容· FORMAT——磁盘格式化· DISKCOPY——全盘复制 外部命令· BACKUP——文件备份· CHKDSK——检查磁盘

文件系统

v 文件基本概念?文件是存放在外存上的一组相关信息的集合,文件中的信息可以是文字、图形、图像、声音等, 也可以是一个程序。vv每个文件必须有名字,操作系统对文件的组织和管理都是按文件名进行的。

?文件基本属性v 文件名:
文件名. 扩展名,例如:文件类型v文件属性v文件操作

操作系统基础知识大全 第4篇

1、操作系统的四个特征

有以下四个特征:

并发

共享

虚拟

异步

接下来,我们分别来搞定每一个特征。

并发是什么?和并行有啥区别?

举个例子,假如你在语音跟同学玩英雄联盟:

你一边用鼠标移动打游戏,同时语音嘴里说"队友挂机,真坑!", 这叫并行(边移动鼠标边语音BB)

你一边用鼠标移动打游戏,然后离开鼠标,去砸键盘, 这叫并发(先离开鼠标然后砸键盘)

并发只是把时间分成若干段,使多个任务交替的执行。

并行的关键是你有同时处理多个任务的能力。

所以我认为它们最关键的点就是:是否是『同时』

那么对于操作系统而言,操作系统的并发性指计算机系统中同时存在多个运行着的程序。

比如说以前的计算机是单核CPU,那么如何在操作系统上同时运行QQ、浏览器,记事本、ppt等多个程序呢,这就需要操作系统具有并发性

CPU时间片(操作系统分配给每个正在运行的进程微观上的一段CPU时间)轮着给进程执行的时间,因为执行速度很快,看起来就像浏览器能同时执行任务一样。

有人会说,现在都多核CPU了,还需要并发吗,答案肯定是需要的,比如你有8核CPU,但是桌面要执行的任务很可能超过8个。

共享是什么?共享和并发有什么关系?

举一个例子:

你同时用QQ和微信发"年终述职.ppt"文件给领导,这时候QQ和微信都在读取这个ppt文件

两个进程正在并发执行(并发性)

需要共享地访问硬盘资源(共享性)

如果没有并发,也就是只有一个进程在运行,那就没有共享了。如果没有共享,QQ和微信就不能同时发文件,无法同时访问硬盘资源,也就无法并发。

其中共享分为两种情况:

上面的例子,QQ和微信都要访问同一个文件,属于同时共享。

对于互斥共享,比如打印机,只能同一时刻被一个进程控制,如打印机,虽然他可以提供多个进程使用,但是试想,同时打印多个东西,会造成打印结果的混乱,因此规定,某些资源在进行使用的时候,必须要先让某进程先使用,等使用完之后,再同一其他进程进行访问。

我们把一段时间内只允许一个进程访问的资源称为独占资源,或临界资源。

虚拟是啥?

先举例,再说定义。

假如一个叫范桶的货车司机在玩英雄联盟,平时因为酒驾太多,自己装了很多次别人的车,住院也花了不少钱,所以家里没钱,只能买个1G内存的二手电脑玩游戏。可英雄联盟至少需要2G内存,这就奇怪了,老司机虽然一到团战就卡死,但是还是能运行英雄联盟。为什么需要2G内存的游戏,1G电脑还能运行呢?

这就是虚拟存储器技术。实际上只有1G内存,在用户看来远远大于1G。

还有,范桶的电脑还是单核的,但范桶居然能一边迅雷下着爱情动作片,一边听着网易云音乐,还在QQ上撩妹子,既然一个程序要被分配CPU才能正常执行,按道理来说同一时间只有1个程序在运行,为啥电脑能同时运行这么多程序呢?

这就是虚拟处理器技术。实际上只有一个CPU,在用户看来有3个CPU在同时服务。(因为CPU来回切换进程的速度特别块,感觉就像很多CPU在为我们服务)

虚拟这块的总结如下:

异步性是啥?

异步在JS里是很常见的,比如aja__请求,我们发出请求后并不是立马得到信息,也不会去等待aja__结果返回,而是继续执行下面的代码,等aja__结果回来,通知JS线程。这就跟CPU处理进程很类似。

比如,CPU正在执行一个进程,进程需要读取文件,读取文件可能要1个小时,那CPU不可能一直等一个小时,CPU会继续把时间片分给别的进程,等文件读取完成了(类似aja__返回结果了),CPU再继续执行之前被中断的进程。

所以异步性就是描述进程这种以不可预知的速度走走停停、何时开始何时暂停何时结束不可预知的性质。

2、操作系统运行机制和体系结构

预备知识:什么是指令

比如说,如下图(简单扫一下即可):

a+b是一段程序代码,a+b在CPU看来并不能一步完成,可以翻译成如下:

// 意思是将内存的16号单元数据,放到A寄存器,LOAD A, 16// 意思是将内存的16号单元数据,放到B寄存器LOAD B, 17// 存器里的A,B数据相加,得到CADD C, A, B

这里就可以看得出来,指令是CPU能识别和执行的最基本命令。

两种指令、两种处理器状态、两种程序

假如说一个用户可以随意把服务器上的所有文件删光,这是很危险的。所以有些指令普通用户是不能使用的,只能是权限较高的用户能使用。此时指令就分为了两种,如下图:

这就引出一个问题:CPU如何判断当前是否可以执行特权指令?

如下图:

CPU通常有两种工作模式即:内核态和用户态,而在PSW(这个不用管,就知道有一个寄存器的标志位0表示用户态,1表示核心态)中有一个二进制位控制这两种模式。

对于应用程序而言,有的程序能执行特权指令,有的程序只能执行非特权指令。所以操作系统里的程序又分为两种:

操作系统内核简单介绍

从下图,我们先看看操作系统内核包含哪些

操作系统内核中跟硬件紧密相关的部分有:

时钟管理。操作系统的时钟管理是依靠硬件定时器的(具体硬件怎么实现我也不太清楚,好像是靠硬件周期性的产生一个脉冲信号实现的)。时钟管理相当重要,比如我们获取时间信息,进程切换等等都是要依靠时钟管理。

中断处理(下一小节会详细介绍)。

原语(后面会有案例提到)。现在可以简单理解为用来实现某个特定功能,在执行过程中不可被中断的指令集合。原语有一个非常重要的特性,就是原子性(其运行一气呵成,不可中断)。

中断

在程序运行过程中,系统出现了一个必须由CPU立即处理的情况,此时,CPU暂时中止程序的执行转而处理这个新的情况的过程就叫做中断。

下面举一个例子:

第一个应用程序在用户态执行了一段时间后

接着操作系统切换到核心态,处理中断信号

操作系统发现中断的信号是第一个程序的时间片(每个程序不能一直执行,CPU会给每个程序一定的执行时间,这段时间就是时间片)用完了,应该换第二个应用程序执行了

切换到第2个进程后,操作系统会将CPU的使用权交换给第二个应用程序,接着第二个应用程序就在用户态下开始执行。

进程2需要调用打印机资源,这时会执行一个系统调用(后面会讲系统调用,这里简单理解为需要操作系统进入核心态处理的函数),让操作系统进入核心态,去调用打印机资源

打印机开始工作,此时进程2因为要等待打印机启动,操作系统就不等待了(等到打印机准备好了,再回来执行程序2),直接切换到第三个应用程序执行

等到打印机准备好了,此时打印机通过I/O控制器会给操作系统发出一个中断信号,操作系统又进入到核心态,发现这个中断是因为程序2等待打印机资源,现在打印机准备好了,就切换到程序2,切换到用户态,把CPU给程序2继续执行。

好了,现在可以给出一个结论,就是用户态、核心态之间的切换是怎么实现的?

"用户态 ---> 核心态"是通过中断实现的。并且中断时唯一途径。

"核心态 ---> 用户态"的切换时通过执行一个特权指令,将程序状态的标志位设为用户态。

中断的分类

举一个例子,什么是内中断和外中断:

接着说之前的范桶同学,小时候不爱学习,每次学习着学习着突然异想天开,回过神来已经过好好长一段时间,这是内部中断。想着想着老师走过来,给了范捅一嘴巴,这是外部中断。

官方解释如下:

内中断常见的情况如程序非法操作(比如你要拿的的数据的内存地址不是内存地址,是系统无法识别的地址),地址越界(比如系统给你的程序分配了一些内存,但是你访问的时候超出了你应该访问的内存范围)、浮点溢出(比如系统只能表示到的范围,你输入一个100, 超出了计算机能处理的范围),或者异常,陷入trap(是指应用程序请求系统调用造成的,什么是系统调用,后面小节会举例讲)。

外中断常见的情况如I/O中断(由I/O控制器产生,用于发送信号通知操作完成等信号,比如进程需要请求打印机资源,打印机有一个启动准备的过程,准备好了就会给CPU一个I/O中断,告诉它已经准备好了)、时钟中断(由处理器内部的计时器产生,允许操作系统以一定规程执行函数,操作系统每过大约15ms会进行一次线程调度,就是利用时钟中断来实现的)。

系统调用

为什么需要系统调用?

比如你的程序需要读取文件信息,可读取文件属于读取硬盘里的数据,这个操作应该时CPU在内核态去完成的,我们的应用程序怎么让CPU去帮助我们切换到内核态完成这个工作呢,这里就需要系统调用了。

这里就引出系统调用的概念和作用。

应用程序通过系统调用请求操作系统的服务。系统中的各种共享资源都由操作系统统一管理,因此在用户程序中,凡是与资源有关的操作(如存储分配、I/O操作、文件管理等),都必须通过系统调用的方式向操作系统提出服务请求,由操作系统代为完成。

以下内容简单看一下即可,系统调用的分类:

需要注意的是,库函数和系统调用容易混淆。

库是可重用的模块 处于用户态

进程通过系统调用从用户态进入内核态, 库函数中有很大部分是对系统调用的封装

举个例子:比如windows和linu__中,创建进程的系统调用方法是不一样的。但在node中的只需要调用相同函数方法就可以创建一个进程。例如

// 引入创建子进程的模块const childProcess = require("child_process")// 获取cpu的数量const cpuNum = require("os").cpus().length// 创建与cpu数量一样的子进程for (let i = 0; i < cpuNum; ++i) { ("")}

进程的定义、组成、组织方式、状态与转换

为什么要引入进程的概念呢?

早期的计算机只支持单道程序(是指所有进程一个一个排队执行,A进程执行时,CPU、内存、I/O设备全是A进程控制的,等A进程执行完了,才换B进程,然后对应的资源比如CPU、内存这些才能换B用)。

现代计算机是多道程序执行,就是同时看起来有多个程序在一起执行,那每个程序执行都需要系统分配给它资源来执行,比如CPU、内存。

拿内存来说,操作系统要知道给A程序分配的内存有哪些,给B程序分配的内存有哪些,这些都要有小本本记录下来,这个小本本就是进程的一部分,进程的一大职责就是记录目前程序运行的状态。

系统为每个运行的程序配置一个数据结构,称为进程控制块(PCB),用来描述进程的各种信息(比如代码段放在哪)。

进程的定义?

简要的说,进程就是具有独立功能的程序在数据集合上运行的过程。(强调动态性)

PCB有哪些组成

如下图,分别说明一下

进程标识符PID相当于身份证。是在进程被创建时,操作系统会为该进程分配一个唯一的、不重复的ID,用于区分不同的进程。

用户标识符UID用来表示这个进程所属的用户是谁。

进程当前状态和优先级下一小节会详细介绍

程序段指针是指当前进程的程序在内存的什么地方。

数据段指针是指当前进程的数据在内存的什么地方。

键盘和鼠标是指进程被分配得到的I/O设备。

各种寄存器值是指比如把程序计数器的值,比如有些计算的结果算到一半,进程切换时需要把这些值保存下来。

进程的组织

在一个系统中,通常由数十、数百乃至数千个PCB。为了对他们加以有效的管理,应该用适当的方式把这些PCB组织起来。这里介绍一种组织方式,类似数据结构里的链表。

进程的状态

进程是程序的一次执行。在这个执行过程中,有时进程正在被CPU处理,有时又需要等待CPU服务,可见,进程的 状态是会有各种变化。为了方便对各个进程的管理,操作系统需要将进程合理地划分为几种状态。

进程的三种基本状态:

进程的另外两种状态:

进程状态的转换

进程的状态并不是一成不变的,在一定情况下会动态转换。

以上的这些进程状态的转换是如何实现的呢,这就要引出下一个角色了,叫原语。

原语是不可被中断的原子操作。我们举一个例子看看原语是怎么保证不可中断的。

 原语采用关中断指令和开中断指令实现。

首先执行关中断指令

然后外部来了中断信号,不予以处理

等到开中断指令执行后,其他中断信号才有机会处理。

¨K46K ¨K11K 因为进程是分配系统资源的单位(包括内存地址空间),因此各进程拥有的内存地址空间相互独立。!w=1679&h=683&f=png&s=326726) ¨K47K 因为两个进程的存储空间不能相互访问,所以操作系统就提供的一个内存空间让彼此都能访问,这就是共享存储的原理。其中,介绍一下基于存储区的共享。

在内存中画出一块共享存储区,数据的形式、存放位置都是由进程控制,而不是操作系统。

管道数据是以字符流(注意不是字节流)的形式写入管道,当管道写满时,写进程的write()系统调用将被阻塞,等待读进程将数据取走。当读进程将数据全部取走后,管道变空,此时读进程的read()系统调用将被阻塞。

如果没写满就不允许读。如果都没空就不允许写。

数据一旦被读出,就从管道中被丢弃,这就意味着读进程最多只能有一个。

¨K49K 进程间的数据交换以格式化的消息为单位。进程通过操作系统提供的"发送消息/接收消息"两个原语进行数据交换。其中消息是什么意思呢?就好像你发QQ消息,消息头的来源是你,消息体是你发的内容。

比如你在玩QQ的时候,QQ是一个进程,如果QQ的进程里没有多线程并发,那么QQ进程就只能同一时间做一件事情(比如QQ打字聊天)

但是我们真实的场景是QQ聊天的同时,还可以发文件,还可以视频聊天,这说明如果QQ没有多线程并发能力,QQ能够的实用性就大大降低了。所以我们需要线程,也就是需要进程拥有能够并发多个事件的能力。

信号量主要是来解决进程的同步和互斥的,我们前端需要了解,如果涉及到同步和互斥的关系(我们编程大多数关于流程的逻辑问题,本质不就是同步和互斥吗?) 在操作系统中,常用P、V信号量来实现进程间的同步和互斥,我们简单了解一下一种常用的信号量,记录型信号量来简单了解一下信号量本质是怎样的。(c语言来表示,会有备注) ¨G2G 意思是信号量的结构有两部分组成,一部分是剩余资源value,比如目前有两台打印机空闲,那么剩余资源就是2,谁正在使用打印机,剩余资源就减1。

Struct process __L 意思是,比如2台打印机都有人在用,这时候你的要用打印机,此时会把这个打印机资源的请求放入阻塞队列,L就是阻塞队列的地址。¨G3G 需要注意的是,如果剩余资源数不够,使用block原语使进程从运行态进入阻塞态,并把挂到信号量S的等待队列中。¨G4G 释放资源后,若还有别的进程在等待这个资源,比如打印机资源,则使用wakeup原语唤醒等待队列中的一个进程,该进程从阻塞态变为继续态。¨K53K 为什么要讲这个呢,主要是node的流的机制,本质就是生产者消费者问题,可以简单的看看这个问题如何解决。!生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。这里我们需要两个同步信号量和一个互斥信号量 ¨G5G 生产者代码如下 ¨G6G 消费者代码如下 ¨G7G ¨K54K ¨K19K 内存是计算机其它硬件设备与``CPU沟通的桥梁、中转站。程序执行前需要先放到内存中才能被CPU处理。

cpu如何区分执行程序的数据在内存的什么地方

是通过给内存的存储单元编址实现的。(存储单元一般是以字节为单位)

如下图,内存的存储单元,就像一个酒店的房间,都有编号,比如程序一的数据都在1楼,1楼1号存储着程序里let a = 1这段代码。

内存管理-内存空间的分配与回收

内存分配分为连续分配和非连续分配,连续分配是指用户进程分配的必须是一个连续的内存空间。

这里我们只讲连续分配中的动态分区分配。

什么是动态分区分配呢,这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。(比如,某计算机内存大小64MB,系统区8MB,用户区56MB…,现在我们有几个进程要装入内存,如下图)

随之而来的问题就是,如果此时进程1使用完了,相应在内存上的数据也被删除了,那么空闲的区域,后面该怎么分配(也就是说随着进程退出,会有很多空闲的内存区域出现)

我们讲一种较为简单的处理方法叫空闲分区表法来解决这个问题。如下图,右侧的表格就是一个空闲分区表。

当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配呢,例如下图,分别有20MB,10MB,4MB三个空闲分区块,现在进程5需要4MB空闲分区,改怎么分配呢?

我们需要按照一定的动态分区分配算法,比如有首次适应算法,指的是每次都从低地址开始查找,找到第一个能满足大小的空闲分区。还有比如最佳适应算法,指的是从空闲分区表中找到最小的适合分配的分区块来满足需求。

连续分配缺点很明显,大多数情况,需要分配的进程大小,不能跟空闲分区剩下的大小完全一样,这样就产生很多很难利用的内存碎片。

这里我们介绍一种更好的空闲分区的分配方法,基本分页存储。如下图

将内存空间分为一个个大小相等的分区(比如:每个分区4KB).每个分区就是一个“页框”。页框号从0开始。

将用户进程的地址空间分为与页框大小相等的一个个区域,称为“页”。每个页也是从0开始。

进程的页与内存的页框有着一一对应的关系。各个页不必连续存放,也不必按先后顺序来,可以放到不相邻的各个页框中。

5 文件管理

文件是什么?

文件就是一组有意义的信息/数据集合。

计算机中存放了各种各样的文件,一个文件有哪些属性呢?文件内部的数据应该怎样组织起来?文件之间又该怎么组织起来?

文件的属性

文件名。即文件的名字,需要注意的是,同一目录下不允许有重名的文件。

标识符。操作系统用于区分各个文件的一种内部的名称。

类型。文件的类型。

位置。文件存放的路径,同时也是在硬盘里的位置(需要转换成物理硬盘上的地址)

创建时间、上次修改时间、文件所有者就是字面意思。

保护信息。比如对这个文件的执行权限,是否有删除文件权限,修改文件权限等等。

文件内部数据如何组织在一起

如下图,文件主要分为有结构文件和无结构文件。

文件之间如何组织起来

通过树状结构组织的。例如windows的文件间的组织关系如下:

接下来我们详细的了解一下文件的逻辑结构

文件的逻辑结构

逻辑结构是指,在用户看来,文件内部的数据是如何组织起来的,而“物理结构”是在操作系统看来,文件是如何保存在外存,比如硬盘中的。

比如,“线性表”就是一种逻辑结构,在用户看来,线性表就是一组有先后关系的元素序列,如:a,b,c,d,

“线性表”这种逻辑结构可以用不同的物理结构实现,比如:顺序表/链表。顺序表的各个元素在逻辑上相邻,在物理上也相邻:而链表的各个元素在物理上可以是不相邻的。

因此,顺序表可以实现“随机访问”,而“链表”无法实现随机访问。

接下来我了解一下有结构文件的三种逻辑结构

顺序文件

什么是顺序文件

指的是文件中的记录一个接一个地在逻辑上是顺序排列,记录可以是定长或变长,各个记录在物理上可以顺序存储或链式存储

顺序文件按结构来划分,可以分为串结构和顺序结构。

串结构是指记录之间的顺序与关键字无关,通常都是按照记录的时间决定记录的顺序。

顺序结构就必须保证记录之间的先后顺序按关键字排列。

这里需要注意的知识点是,顺序文件的存储方式和是否按关键字排列,会影响数据是否支持随机存取和是否可以快速按关键字找到对应记录的功能。

索引文件

对于可变长记录文件,要找到第i个记录,必须先顺序查找前i-1个记录,但是很多场景中又必须使用可变长记录,如何解决这个问题呢?这就引出来马上讲的索引文件

给这些变长的记录都用一张索引表来记录,一个索引表项包括了索引号,长度和指针。

其中,可以将关键字作为索引号的内容,如果关键字本身的排列是有序的,那么还可以按照关键字进行折半查找。

但是建立索引表的问题也很明显,首先若要删除/增加一个记录,同时也要对索引表操作,其次,如果增加一条记录才1KB,但是索引表增加i一条记录可能有8KB,以至于索引表的体积大大多于记录。存储空间的利用率就比较低。

索引顺序文件

索引顺序文件是索引文件和顺序文件思想的结合。索引顺序文件中,同样会为文件建立一张索引表,但不同的是,并不是每个记录对应一个索引表项,而是一组记录对应一个索引表项。

文件目录

首先,我们需要了解一下文件控制块是什么。我们假设目前在windows的D盘,如下图

可以看到,目录本身就是一种有结构的文件,记录了目录里的文件和目录的信息,比如名称和类型。而这些一条条的记录就是一个个的“文件控制块”(FCB)。

文件目录的结构通常是树状的,例如linu__里/是指根路径,/home是根路径下的二级目录

需要注意的是,树状目录不容易实现文件共享,所以在树形目录结构的基础上,增加了一些指向同一节点的有向边(可以简单理解为引用关系,就跟js里的对象一样)

也就是说需要为每个共享节点设置一个共享计数器,用于记录此时有多少个地方在共享该结点。只有共享计数器减为0,才删除该节点。

文件存储空间管理

首先,我们了解一下磁盘分为目录区和文件区。

接着,我们了解一下常见的两种文件存储空间的管理算法,如下图,假如硬盘上空闲的数据块是蓝色,非空闲的数据块是橙色。

对分配连续的存储空间,可以采用空闲表法(只讲这种较简单的方法)来分配和回收磁盘块。对于分配,可以采用首次适应,最佳适应等算法来决定要为文件分配哪个区间。(空闲表表示如下)

首次适应是指当要插入数据的时候,空闲表会依次检查空闲表中的表项,然后找到第一个满足条件的空闲区间。

最佳适应算法是指当要插入数据的时候,空闲表会依次检查空闲表中的表项,然后找到满足条件而且空闲块最小的空闲区间。

如何回收磁盘块呢,主要分为以下4中情况

回收区的前后没有相邻空闲区

回收区前后都是空闲区

回收区前面是空前去

回收区后面是空闲区

最重要的是要注意表项合并的问题。(比如说回收区前后都有空闲区就将其一起合并为一个空闲区)

文件共享

文件共享分为两种

注意,多个用户共享同一个文件,意味着系统只有“一份”文件数据。并且只要某个用户修改了该文件的数据,其他用户也可以看到文件的变化。

软连接可以理解为windows里的快捷方式。

硬链接可以理解为js里的引用计数,只有引用为0的时候,才会真正删除这个文件。

文件保护

操作系统需要保护文件的安全,一般有如下3种方式:

口令保护。是指为文件设置一个“口令”(比如123),用户请求访问该文件时必须提供对应的口令。口令一般放在文件对应的FCB或者索引结点上。

加密保护。使用某个"密码"对文件进行加密,在访问文件时需要提供正确的“密码”才能对文件进行正确的解密。

访问控制。在每个文件的FCB或者索引节点种增加一个访问控制列表,该表中记录了各个用户可以对该文件执行哪些操作。

6 I/O设备

什么是I/O设备

I/O就是输入输出(Input/Output)的意思,I/O设备就是可以将数据输入到计算机,或者可以接收计算机输出数据的外部设备,属于计算机中的硬件部件。

I/O设备分类--按使用特性

人机交互类设备,这类设备传输数据的速度慢

存储设备,这类设备传输数据的速度较快

网络通信设备,这类设备的传输速度介于人机交互设备和存储设备之间

I/O控制器

CPU无法直接控制I/O设备的机械部件,因此I/O设备还要有一个电子部件作为CPU和I/O设备机械部件之间的“中介”,用于实现CPU对设备的控制。这个电子部件就是I/O控制器。

接收和识别CPU发出的指令是指,比如CPU发来读取文件的命令,I/O控制器中会有相应的控制寄存器来存放命令和参数

向cpu报告设备的状态是指,I/O控制器会有相应的状态寄存器,用来记录I/O设备是否空闲或者忙碌

数据交换是指I/O控制器会设置相应的数据寄存器。输出时,数据寄存器用于暂存CPU发来的数据,之后再由控制器传送给设备。

地址识别是指,为了区分设备控制器中的各个寄存器中的各个寄存器,也需要给各个寄存器设置一个特性的“地址”。I/O控制器通过CPU提供的“地址”来判断CPU要读写的是哪个寄存器

I/O控制方式

这里我们指讲一下目前比较先进的方式,通道控制方式。

通道可以理解为一种“弱鸡版CPU”。通道可以识别并执行一系列通道指令。

通道最大的优点是极大的减少了CPU的干预频率,I/O设备完成任务,通道会向CPU发出中断,不需要轮询来问I/O设备是否完成CPU下达的任务。

操作系统基础知识大全 第5篇

操作系统的三个要素

操作系统的定位是计算机资源(CPU,内存,硬盘,各种I/O设备等)的管理者。最早的计算机系统一次只运行一个程序,操作系统是作为库函数的形式存在的,这种模式无法充分的利用计算机资源,对于早期造价动辄数百万美元的计算机来说,这是巨大的浪费,因此人们引入了现代的操作系统来支持方便的多进程并发执行,允许多个用户同时运行他们的程序。具体来说,操作系统提供了这么三个要素:

虚拟化(Virtualization),主要指的是CPU和内存虚拟化,仿佛每个进程都有自己独占的CPU和内存。

并发(Concurrency),主要指的是线程级的并发。

持久化(Persistance),主要指的是文件系统。

存储器层次结构

为什么说单个程序不能充分利用计算机资源呢?这跟计算机的存储器层次结构有关,计算机中有各种各样的存储器:CPU上的寄存器、一二级缓存,内存、硬盘……这些存储器的容量、性能和成本各不相同,一个典型的存储器层次结构如下:

越是靠近上层(CPU)存储器的性能越好,但是容量越小,(每字节)存储成本越高;越是远离CPU,存储器的性能越差,但是容量越大,(每字节)存储成本越低。比如,CPU访问一级缓存缓存只需要1个时钟周期,而进行磁盘I/O可能需要上千万个时钟周期。程序在进行I/O操作的时候,CPU实际是空闲的,这时候可以让CPU运行其他程序,提供计算机资源的利用率。

另一方面,为了弥补高速CPU到低速I/O设备之间的差距,在存储器之间引入了多层的缓存,比如本地硬盘作为网络的缓存,内存(DRAM)作为硬盘的缓存,SRAM作为内存的缓存。由于局部性原理的存在,这个存储器层次结构通常工作得很好。所谓得局部性原理包含两项:

一是时间局部性,程序一旦引用过某个存储器位置,接下来它很可能还会引用这个位置;

二是空间局部性,程序一旦引用过某个存储器位置,接下来它很可能还会引用附近的位置。

进程

操作系统提供了进程这个抽象概念,一个进程就是一个正在运行的程序。根据Steam 20XX年5月的调查,现在主流的PC配置是64位的4核物理CPU和16G内存[1],而目前__86_64的PC上通常会运行几十上百个进程,每个进程拥有256TB的的虚拟内存。正是通过CPU和内存虚拟化,操作系统提供了这种幻象:似乎每一个进程都有一个独占的CPU和一片巨大的独占内存。

在深入这些细节以前,我们先来看看计算机上运行一个进程需要维护些什么状态信息:

用来存取指令和数据的内存,由于进程会根据地址来读写内存,它们也叫做内存地址空间,当然这里指的虚拟内存地址空间(Virtual Memory Address Space)。进程的堆栈信息也在这个地址空间中。

CPU中的通用寄存器,如%ra__

CPU中的特殊寄存器,如:

程序计数器(Program Counter/PC),或叫做指令指针(Instruction Pointer/IP)

栈指针(stack pointer)及其对应的基址指针(frame pointer)

I/O相关的信息,比如当前打开的文件,Socket套接字等。

操作系统通过分时复用的方式实现了CPU的虚拟化,运行进程A一段时间后,主动或被动地把这个进程的状态信息写入物理内存然后从物理内存中读取另一个进程B的状态信息,从而恢复进程B的运行。

进程在其生命周期中,始终处于以下三个状态中的一个:

Running:进程正在通过CPU执行指令

Ready:进程可以运行,但是操作系统还没有调度它

Blocked:进程在等待某个事件发生(比如等待磁盘读取完成),因此还不能运行

这是一个理想化的状态,Linu__中进程还有一些别的状态

内核中有一个数据结构叫做Process Control Block(PCB),用来记录上面提到的各种信息,每个进程都有一个对应的PCB。

CPU虚拟化

下面来考虑实现CPU虚拟化要解决的两个核心问题:

安全:用户的进程不应该拥有无限制的权限,比如它不应该能访问另一个用户的文件,而权限检查的把关就需要由操作系统来实现。

性能:操作系统提供CPU虚拟化这种抽象机制的时候,不应该有太大的性能损失

计算机系统采用了一种叫Limited Direct E__ecution的机制,通过硬件和操作系统的协作解决了这两个问题。在具体实现上,CPU中有一个状态位,表明了当前运行在什么模式下:

用户的进程运行在用户模式下,这种模式能做的操作有限,比如它无法发起一个I/O请求,尝试这么做会引发一个异常(e__ception),导致进程被操作系统杀死。

与之相对的是,内核代码运行在内核模式下,它能执行所有特权操作,比如发起I/O请求。

如果用户进程需要发起特权操作,必须通过操作系统内核来进行,操作系统提供了很多这样的服务入口,这就是系统调用,比如说打开一个文件用到的open()系统调用。这些系统调用看起来像是一个普通的函数,而内部实现上只是把系统调用的编号,和对应的参数放到栈上某个特定的位置,然后调用trap指令,这个指令会完成以下几个操作:

把当前进程的CPU寄存器的值保存到内核栈中

把运行模式切换为内核模式

跳转到该系统调用的处理函数

内核检查参数和权限和合法性,然后执行相应的处理,无论结果如何,最终调用return-from-trap指令返回用户进程,具体过程如下:

从内核栈中还原该进程的CPU寄存器值

把运行模式切换为用户模式

把程序计数器(PC)设置为进程的下一条指令,从而恢复用户进程的运行。

可以看到,用户进程直接运行在CPU上, 因此保证了性能,而通过内核模式和用户模式的区分保证了安全,这里主要的损耗在于上下文切换带来的开销。

内核调用return-from-trap之前还会检查进程是否有待处理的信号,如果有的话在这里触发信号处理函数。

抢占式调度

Limited Direct E__ecution 存在一个问题,一个进程可能会长久地占用CPU,导致其他进程无法得到服务,那么这个进程什么时候把控制权还给操作系统,让操作系统调度其他进程呢?很自然地,一个合理的时间点是触发系统调用的时候,操作系统可能会决定先执行另一个进程。但如果是一个无限循环,中间没有任何系统调用呢?一些早期的系统如Mac OS采用了合作式的调度方案,长期运行的进程需要周期性地让出CPU,比如在循环体中加入一个yield()之类的系统调用,允许操作系统调度其他进程。这个方案治标不治本,存在这些场景:

某些恶意程序希望独占CPU资源,不按照要求来做

程序bug导致yield()一直没有运行

这种情况下,唯一能打破这种循环的方法只有重启。要解决这个问题,操作系统仍然需要硬件的协助。硬件中有个计时器可以编程为每隔一定的时间(比如每十毫秒)就发起一个时钟中断,它会挂起当前运行的进程,跳转到操作系统预先设置的中断处理函数中。在这里,操作系统可以决定是继续运行这个进程,或是调度别的进程。这就是抢占式调度。

异常处理流

程序运行的过程中会遇到各种各样的异常情况,在计算机启动的时候,操作系统就需要为各种异常指定对应的处理函数。CPU在执行完一条指令之后,总是会检查是否存在异常,如果有则触发对应的异常处理函数,否则继续执行下一条指令。

注意:

上文中有两组寄存器的保存/还原操作,第一组是用户态的寄存器,第二组是内核态的寄存器

内核处理完系统的调用后,也可以选择不切换进程,直接调用return-from-trap返回进程A

进程调度策略

上面描述了进程切换的机制,接下来讨论进程调度的策略,也就是说每次操作系统要调度一个进程的时候,选择运行哪一个进程。通常来说,我们有两种类型的工作负载:

交互式的进程,这种进程大部分时候都在Blocked的状态等待I/O,不怎么占用CPU,但是需要得到高优先级的处理,比如shell里面用户每输入一个字符,总是希望操作系统尽快响应并把这个字符显示到屏幕上。

非交互式的进程,他们大部分时间都在使用CPU执行指令,处于Running的状态,这种进程的诉求是高吞吐量,尽可能减少进程切换带来的开销。

下面来看看两种常见的调度策略

多级反馈队列

多级反馈队列(Multi-Level Feedback Queue)致力于提高系统的整体响应时间。

操作系统中维护多个进程队列,从高到底依次为每个队列分配不同的优先级:高优先级的进程分配较短的时间片,保证快速响应;低优先级的进程分配较长的时间片,保证其高吞吐量。具体调度策略如下:

如果A的优先级大于B,运行A

如果A的优先级等于B,轮流运行A和B

然而我们不知道每个进程的工作模式是交互式的还是非交互式,因此先假设他们都是需要快速响应的交互式进程:

当进程启动的时候,把它放到最高优先级的队列中

当一个进程用完它的时间片之后,降低它的优先级,也就是移到下一个队列中

还存在一个问题,如果有大量高优先级任务,那么低优先的任务可能会被饿死,因此:

每隔一段时间把所有的进程都移动到最高优先级的队列

按比例共享调度

与MLFQ相对的,按比例共享调度(Proportional Share Scheduling)的目标是让各个进程公平地获取CPU时间。它最简单的形式叫做彩票调度(lottery scheduling):假设系统使用100张彩票(编号为0-99),每次随机选择一张来决定运行哪个进程,进程A持有75张(编号为0-74),进程B持有剩余的25张(编号75-99)。任务调度器每次计算出一个0-99之间的随机值,如果落在0-74之间则运行进程A,反之运行进程B,这样保证了两个进程总体获得的CPU时间跟它们持有的票据数量一致(75%:25%)。

最后还有个问题,怎么为进程分配票据(或者说权重),可以跟nice值关联起来。

Linu__的进程调度器

Linu__当前采用的进程调度器叫做完全公平调度器(Completely Fair Scheduler/CFS),内部采用红黑树,实现了跟按比例共享调度类似的目标。之前采用的进程调度器为O(1),其实现类似前面说的多级反馈队列。

操作系统基础知识大全 第6篇

Log-Structured File System

设计思路

LFS的设计思路来自于以下几点观察:

内存变得越来越大,能够缓存越来越多的东西,因此写入性能渐渐地主宰了文件系统的性能

磁盘的随机I/O和顺序I/O的性能相差巨大,如果能把大部分I/O都转换成顺序I/O,将能极大地提高性能

现有的文件系统在许多常见的工作负载下表现都不如意:它们的元数据和数据块是分开的,文件系统写入一个数据块要多次寻道和旋转,虽然FFS通过块组缓解了这个问题,但是依然避免不了大量短距离的寻道和旋转。

文件系统感知不到RAID,难以避免RAID-4/RAID-5的small write问题,即一个小块的数据写入会导致4次物理I/O。

因此,LFS尝试优化磁盘写入性能,尽可能地使用连续I/O,对于磁盘的读取性能则寄希望于内存能缓存更多内容。这个出发点导致了它的数据结构不同与常见的文件系统。

连续写入

LFS所尝试的第一个优化就是在写入数据块的时候,同时在后面写入数据块的inode,比如下图在磁盘地址A0写入一个数据块之后再把它的inode写到后面:

然后对于大量小块的I/O,这样是不行的,因此LFS采用了写缓存技术,先在内存中缓存一定的大小写请求,直到达到一个足够大的值(LFS中称为segment),然后再一次性写入磁盘中。因此LFS的一次I/O通常会包含多个数据块和inode:

那么,多大的segment是合适的呢,这跟磁盘性能有关系,假如说我们希望磁盘95%的时间都在写入,只有5%的时间再寻道,对于一个写入速度为100MiB/s的磁盘来说,这个segment约为9MiB。这里忽略了计算公式,有兴趣请参考43 Log-structured File System (LFS)。

inode

读者们肯定能注意到,数据块和inode混在一起之后,LFS要怎么找到这些inode?我们可以用一个map结构来存储inode,其key是文件的inode number,value是inode再磁盘上的地址,称之为inode map(或imap)。考虑到LFS的设计,imap不应该存储在磁盘的某个特定位置,这会引起来回寻道的问题,因此LFS在一个写I/O的最后把最新的imap也一起写进来了。

下一个问题是,LFS怎么知道最新的imap在什么地方?它必须得把最新imap的地址写在磁盘上一个固定的地方,这就是checkpoint region(CR)。出于写入性能的考虑,CR一般30秒左右才更新一次,因此对性能的影响可以忽略。

目录

前面的讨论仅涉及了文件,其实目录也是类似的,假如在某个目录/dir下面创建了一个叫foo的文件:

LFS首先写入foo的内容和inode

然后写入目录D的内容,即inode number和磁盘地址的映射关系,如下图中的(foo,K),以及这个目录新的inode

最后写入写的imap

文件读取

LFS挂载后,会先读入CR,再根据CR的内容把imap缓存到内存中,之后这两个数据结构的更新就按照上面的描述进行更新,imap在每次写I/O后追加到尾部,CR则定期写入。

从LFS读取一个文件如/dir/foo时,首先从imap缓存中找到根目录/的inode地址(比如根据约定的inode number 2),读取其内容找到dir目录对应的inode number,再根据inode number从imap中找到dir对应的inode number,如此类推直到读入foo的inode,这之后的过程就跟普通uni__文件系统没太大区别了,inode里面有direct pointer, indirect LFS没有对读取做什么优化,而是寄希望于越来越大的内存能够缓存更多的inode和数据块。

垃圾回收

LFS写入新的数据块时,总是寻找一片连续的空闲磁盘空间,然后写入整个segment,因此磁盘中其实充满了过时的数据。比如下面的i节点号为K的文件一开始保存在磁盘地址A0,当这个文件的内容更新的时候,LFS在磁盘地址A4写入了新的数据块和inode,此时A0和A1的数据就是过时的:

另一个例子,假设用户往文件中追加了一个块(A4),这种情况下过时的数据只有老的inode(A1):

在ZFS,btrfs等吸收了LFS设计思路的文件系统中,允许用户保留这些老版本的文件作为snapshot,并把这个feature作为了一个买点,这种方法就是著名的copy on write。而在LFS中,只保留最新版本的文件。

不论如何,这些文件系统最终都需要回收这些不再使用的、过时的数据。一个简单的实现是扫描这些数据,发现过时的数据就标记为空闲,但是这样会造成大量的磁盘碎片。在LFS的实现中,定期启动一个cleaner线程,读出几个segment的数据,其中过时的数据会被直接丢弃,剩余的块则会合并到新的segment中写入磁盘。这个方式保证了磁盘的数据大致是连续的,方便在写入时找到大片的空闲空间。

Solid State Drive

这里的Solid state disk(简称SSD)特指基于NAND Flash的存储设备,SSD不一定需要基于Flash,但是目前NAND Flash是SSD事实的标准,在深入SSD之前我们先了解Flash的特性。

Flash芯片组成

跟磁盘相比,它没有任何机械组件。。Flash芯片最底层的存储单元叫做cell,一个cell可以存储一个或者多个bit:

只存储一个bit的cell叫做single-levle cell(SLC)

存储两个bit的call叫做multi-level cell(MLC)

存储三个bit的call叫做triple-level cell(TLC)

……

总体来说SLC的性能最好成本最高,每个cell的存储的bit数量越多性能就越差,成本也越低。

多个cell组成一个page,这是flash存取数据的最小单元,它的大小通常是几KiB,比如4KiB

多个page组成一个block,它的大小一般是128KiB或256KiB

多个block组成一个bank或者叫(plane),一个flash芯片一般会包含若干个bank

下图是一个缩小了规模的Flash芯片

Flash芯片的基本操作

Flash芯片的物理特性比较特殊,它最基本的底层操作有三种.

读取(read)一个page:flash芯片可以读取任意一个page,只要给出page号即可。不像磁盘,ssd是一种随机存取设备,它没有机械部件,存取任意一个位置的速度都是一样的,读操作通常只要10微秒(10^-5)左右。

擦除(erase)一个block:flash的物理特性要求在写入一个page之前,先擦除改page所在的整个block,整个个操作很慢,一般需要几毫秒(10^-3)。这个操作会把整个block里面每一个比特都设置成1,因此在擦除前需要复制出里面有价值的数据。block擦除完成之后就能够进行编码(或者说写入)。

编码(Program)一个page:在擦除一个block之后,flask可以把里面的一些比特从1改成0,因此把想要的内容写入page中。编码操作通常需要100微秒左右(10^-4)。

总的来说,读取的速度远快于编码的速度,而编码的速度又快于擦除的速度。

Flash磨损

由于没有机械部件,flash的可靠性比磁盘要高很多,不会出现类似磁头划碰的问题,但是flash也有它的弱点,即磨损(wear out):每次擦除一个block或编码一个page时,都会造成一些轻微的损耗,这些损耗积累下来后最终会导致无法区分0和1,这时候这个block就变得不可用了。一般一个基于MLC的芯片生命周期大约是10,000P/E(Program/Erase),也就是说每个block在失效前可以反复擦除和写入10,000次,而基于SLC的芯片生命周期大概是100,000P/E。

从Flash芯片到SSD

前面我们描述了Flash芯片的组成,而一块SSD中会包含多个Flash芯片,它们连接到一个Flash控制器上,Flash控制器对外提供了一个磁盘设备的接口,更有趣的是Flash控制器还连着一小块内存。这片内存可以用来作为I/O的缓存,同时还保存了物理块到Flash 芯片的page的映射关系。

为什么SSD中需要这样一个映射关系?假设我们采用一种最简单的映射关系,把物理块0映射到第0个Flash芯片上第0个page,把物理块1映射到第0个Flash芯片上第个page……这种简单的映射有两个问题,主要出现在更新的场景:

一是性能上的,我们直到page在写入前需要先擦除,这种原地更新导致了三次I/O操作:

读出整个block,并在内存中更新对应的内容

擦除整个block,而flash擦除的速度很慢,跟磁盘基本是一个量级的

重新写入block

第二个问题是,经常更新的磁盘区域(比如swap和/tmp分区)会严重磨损,成为SSD寿命的短板

Flash Translation Layer

因此,Flash控制器最核心的功能就是,在主机发起I/O请求时,动态地完成物理块到SSD内部page的转换,这就是Flash Translation Layer(FTL),它的目标有几个:

并行地利用多个Flash芯片

减少写放大

使得Flash的磨损尽可能的平均

太阳底下无新事,第一个问题可以借鉴RAID,后两者可以从LFS中得到启发。大多数FTL的实现都类似于log-structured file system,当主机往SSD写入内容的时候,先在SSD的内存中缓存一定的大小,然后找到一片空闲的区域一次性的写入;同时SSD的内存和Flash中维护一个物理块和SSD内部page的映射表,即mapping table。假设主机进行了这一系列的操作:

往物理块100写入内容a1

往物理块101写入内容a2

往物理块20XX写入内容b1

往物理块20XX写入内容b2

这一系列的操作会由FTL合并写入到一片临近的区域中,如下图所示,图上Table部分即mapping table。

垃圾回收

假设主机接下来需要修改物理块100和101的内容,分别改成了c1和c2,FTL不会原地修改,而是直接写入到后续的空闲page中,同时在mapping table中修改物理块100和101对应的page为4和5:

此时page 0和1中的数据是过时的,如果需要回收这两个page,FTL必须先把同一个block中有效的数据(page2和3)读取出来,写入到后续的空闲空间中,这个时候整个block0都是过时的数据,FTL才能擦除这个block。

mapping table 大小

按照上面的方式把一个物理块映射到ssd的一个page,如果这两者的大小都为4KiB,对于一个1TiB的SSD来说,mapping table需要有1TiB/4KiB个条目,假设每个条目的大小大小为4字节的话,整个mapping table的大小需要1GiB,对于SSD的内存来说,这实在太大了。一种解决方案是只在SSD中缓存部分活跃的mapping,其余部分持久化到Flash中,如果工作集能满足局部性原理的话,这个方式能保持不错的性能。

另一种方案是把一大块物理块映射到SSD的一个block中,这样mapping table可以非常小,但是它有一个严重的问题,如果只修改block中一个或几个page时,FTL必须把整块内容读取出来,在内存中完成对应page的修改后,再把整个block的内容写到一个新的空闲block中。因此,实践中更常见的做法叫混合mapping,FTL中有两个mapping table,基于page的映射叫log table,基于block的映射叫data table,如果物理块能连续的映射到一个block中则保存到data table,否则保存到log table中。

操作系统基础知识大全 第7篇

一、概述

操作系统基本特征

并发

并发是指宏观上在一段时间内能同时运行多个程序,而并行则指同一时刻能运行多个指令。

并行需要硬件支持,如多流水线或者多处理器。

操作系统通过引入进程和线程,使得程序能够并发运行。

共享

共享是指系统中的资源可以被多个并发进程共同使用。

有两种共享方式:互斥共享和同时共享。

互斥共享的资源称为临界资源,例如打印机等,在同一时间只允许一个进程访问,需要用同步机制来实现对临界资源的访问。

虚拟

虚拟技术把一个物理实体转换为多个逻辑实体。

利用多道程序设计技术,让每个用户都觉得有一个计算机专门为他服务。

主要有两种虚拟技术:时分复用技术和空分复用技术。例如多个进程能在同一个处理器上并发执行使用了时分复用技术,让每个进程轮流占有处理器,每次只执行一小个时间片并快速切换。

异步

异步指进程不是一次性执行完毕,而是走走停停,以不可知的速度向前推进。

但只要运行环境相同,OS需要保证程序运行的结果也要相同。

操作系统基本功能

进程管理

进程控制、进程同步、进程通信、死锁处理、处理机调度等。

内存管理

内存分配、地址映射、内存保护与共享、虚拟内存等。

文件管理

文件存储空间的管理、目录管理、文件读写管理和保护等。

设备管理

完成用户的 I/O 请求,方便用户使用各种设备,并提高设备的利用率。

主要包括缓冲管理、设备分配、设备处理、虛拟设备等。

系统调用

如果一个进程在用户态需要使用内核态的功能,就进行系统调用从而陷入内核,由操作系统代为完成。

大内核和微内核

大内核

大内核是将操作系统功能作为一个紧密结合的整体放到内核。

由于各模块共享信息,因此有很高的性能。

微内核

由于操作系统不断复杂,因此将一部分操作系统功能移出内核,从而降低内核的复杂性。移出的部分根据分层的原则划分成若干服务,相互独立。

在微内核结构下,操作系统被划分成小的、定义良好的模块,只有微内核这一个模块运行在内核态,其余模块运行在用户态。

因为需要频繁地在用户态和核心态之间进行切换,所以会有一定的性能损失。

中断分类

外中断

由 CPU 执行指令以外的事件引起,如 I/O 完成中断,表示设备输入/输出处理已经完成,处理器能够发送下一个输入/输出请求。此外还有时钟中断、控制台中断等。

异常

由 CPU 执行指令的内部事件引起,如非法操作码、地址越界、算术溢出等。

什么是堆和栈?说一下堆栈都存储哪些数据?

栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。

数据结构中这两个完全就不放一块来讲,数据结构中栈和队列才是好基友,我想新手也很容易区分。

我想需要区分的情况肯定不是在数据结构话题下,而大多是在 OS 关于不同对象的内存分配这块上。

简单讲的话,在 C 语言中:

int a[N]; // go on a stackint__ a = (int __)malloc(sizeof(int) __ N); // go on a heap

如何理解分布式锁?

分布式锁,是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。

二、进程管理

进程与线程

进程

进程是资源分配的基本单位,用来管理资源(例如:内存,文件,网络等资源)

进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。(PCB是描述进程的数据结构)

下图显示了 4 个程序创建了 4 个进程,这 4 个进程可以并发地执行。

线程

线程是独立调度的基本单位。

一个进程中可以有多个线程,它们共享进程资源。

QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。

区别

(一)拥有资源

进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。

(二)调度

线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。

(三)系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。

(四)通信方面

进程间通信 (IPC) 需要进程同步和互斥手段的辅助,以保证数据的一致性。而线程间可以通过直接读/写同一进程中的数据段(如全局变量)来进行通信。

进程状态的切换(生命周期)

就绪状态(ready):等待被调度

运行状态(running)

阻塞状态(waiting):等待资源

应该注意以下内容:

只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度。

阻塞状态是缺少需要的资源从而由运行状态转换而来,但是该资源不包括 CPU 时间,缺少 CPU 时间会从运行态转换为就绪态。

进程只能自己阻塞自己,因为只有进程自身才知道何时需要等待某种事件的发生

进程调度算法

不同环境的调度算法目标不同,因此需要针对不同环境来讨论调度算法。

批处理系统

批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。

先来先服务

先来先服务 first-come first-serverd(FCFS)

按照请求的顺序进行调度。

有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。

短作业优先

短作业优先 shortest job first(SJF)

按估计运行时间最短的顺序进行调度。

长作业有可能会饿死,处于一直等待短作业执行完毕的状态。因为如果一直有短作业到来,那么长作业永远得不到调度。

最短剩余时间优先

最短剩余时间优先 shortest remaining time ne__t(SRTN)

按估计剩余时间最短的顺序进行调度。

交互式系统

交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。

时间片轮转

将所有就绪进程按 FCFS (先来先服务) 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。

时间片轮转算法的效率和时间片的大小有很大关系。因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。

优先级调度

为每个进程分配一个优先级,按优先级进行调度。

为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

多级反馈队列

如果一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法,那么需要交换 100 次。

多级队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不同,例如 1,2,4,8,。进程在第一个队列没执行完,就会被移到下一个队列。这种方式下,之前的进程只需要交换 7 次。

每个队列优先权也不同,最上面的优先权最高。因此只有上一个队列没有进程在排队,才能调度当前队列上的进程。

可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。

实时系统

实时系统要求一个请求在一个确定时间内得到响应。

分为硬实时和软实时,前者必须满足绝对的截止时间,后者可以容忍一定的超时。

参考资料:

操作系统典型调度算法_C语言中文网

进程同步

临界区

对临界资源进行访问的那段代码称为临界区。

为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。

// entry section// critical section;// e__it section

同步与互斥

同步:多个进程按一定顺序执行;

互斥:多个进程在同一时刻只有一个进程能进入临界区。

信号量

P 和 V 是来源于两个荷兰语词汇,P() ---prolaag (荷兰语,尝试减少的意思),V() ---verhoog(荷兰语,增加的意思)

信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。

down : 如果信号量大于 0 ,执行 -1 操作;如果信号量等于 0,进程睡眠,等待信号量大于 0;(阻塞)

up :对信号量执行 +1 操作,唤醒睡眠的进程让其完成 down 操作。(唤醒)

down 和 up 操作需要被设计成原语,不可分割,通常的做法是在执行这些操作的时候屏蔽中断。

如果信号量的取值只能为 0 或者 1,那么就成为了 互斥量(Mute__) ,0 表示临界区已经加锁,1 表示临界区解锁。

typedef int semaphore;semaphore mute__ = 1;void P1() { down(&mute__); // 临界区 up(&mute__);}void P2() { down(&mute__); // 临界区 up(&mute__);}

使用信号量实现生产者-消费者问题

问题描述:使用一个缓冲区来保存物品,只有缓冲区没有满,生产者才可以放入物品;只有缓冲区不为空,消费者才可以拿走物品。

因为缓冲区属于临界资源,因此需要使用一个互斥量 mute__ 来控制对缓冲区的互斥访问。

为了同步生产者和消费者的行为,需要记录缓冲区中物品的数量。数量可以使用信号量来进行统计,这里需要使用两个信号量:empty 记录空缓冲区的数量,full 记录满缓冲区的数量。其中,empty 信号量是在生产者进程中使用,当 empty 不为 0 时,生产者才可以放入物品;full 信号量是在消费者进程中使用,当 full 信号量不为 0 时,消费者才可以取走物品。

注意,不能先对缓冲区进行加锁,再测试信号量。也就是说,不能先执行 down(mute__) 再执行 down(empty)。如果这么做了,那么可能会出现这种情况:生产者对缓冲区加锁后,执行 down(empty) 操作,发现 empty = 0,此时生产者睡眠。消费者不能进入临界区,因为生产者对缓冲区加锁了,也就无法执行 up(empty) 操作,empty 永远都为 0,那么生产者和消费者就会一直等待下去,造成死锁。

#define N 100typedef int semaphore;semaphore mute__ = 1;semaphore empty = N;semaphore full = 0;void producer() { while(TRUE){ int item = produce_item(); // 生产一个产品 // down(&empty) 和 down(&mute__) 不能交换位置,否则造成死锁 down(&empty); // 记录空缓冲区的数量,这里减少一个产品空间 down(&mute__); // 互斥锁 insert_item(item); up(&mute__); // 互斥锁 up(&full); // 记录满缓冲区的数量,这里增加一个产品 }}void consumer() { while(TRUE){ down(&full); // 记录满缓冲区的数量,减少一个产品 down(&mute__); // 互斥锁 int item = remove_item(); up(&mute__); // 互斥锁 up(&empty); // 记录空缓冲区的数量,这里增加一个产品空间 consume_item(item); }}

管程

管程 (英语:Monitors,也称为监视器) 是一种程序结构,结构内的多个子程序(对象或模块)形成的多个工作线程互斥访问共享资源。

使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。

管程是为了解决信号量在临界区的 PV 操作上的配对的麻烦,把配对的 PV 操作集中在一起,生成的一种并发编程方法。其中使用了条件变量这种同步机制。

c 语言不支持管程,下面的示例代码使用了类 Pascal 语言来描述管程。示例代码的管程提供了 insert() 和 remove() 方法,客户端代码通过调用这两个方法来解决生产者-消费者问题。

monitor ProducerConsumer integer i; condition c; procedure insert(); begin // end; procedure remove(); begin // end;end monitor;

管程有一个重要特性:在一个时刻只能有一个进程使用管程。进程在无法继续执行的时候不能一直占用管程,否者其它进程永远不能使用管程。

管程引入了 条件变量 以及相关的操作:wait() 和 signal() 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程。

使用管程实现生产者-消费者问题

// 管程monitor ProducerConsumer condition full, empty; integer count := 0; condition c; procedure insert(item: integer); begin if count = N then wait(full); insert_item(item); count := count + 1; if count = 1 then signal(empty); end; function remove: integer; begin if count = 0 then wait(empty); remove = remove_item; count := count - 1; if count = N -1 then signal(full); end;end monitor;// 生产者客户端procedure producerbegin while true do begin item = produce_item; (item); endend;// 消费者客户端procedure consumerbegin while true do begin item = ; consume_item(item); endend;

经典同步问题

生产者和消费者问题前面已经讨论过了。

读者-写者问题

允许多个进程同时对数据进行读操作,但是不允许读和写以及写和写操作同时发生。读者优先策略

Rcount:读操作的进程数量(Rcount=0)

CountMute__:对于Rcount进行加锁(CountMute__=1)

WriteMute__:互斥量对于写操作的加锁(WriteMute__=1)

Rcount = 0;semaphore CountMute__ = 1;semaphore WriteMute__ = 1;void writer(){ while(true){ sem_wait(WriteMute__); // TO DO write(); sem_post(WriteMute__); }}// 读者优先策略void reader(){ while(true){ sem_wait(CountMute__); if(Rcount == 0) sem_wait(WriteMute__); Rcount++; sem_post(CountMute__); // TO DO read(); sem_wait(CountMute__); Rcount--; if(Rcount == 0) sem_post(WriteMute__); sem_post(CountMute__); }}

哲学家进餐问题

五个哲学家围着一张圆桌,每个哲学家面前放着食物。哲学家的生活有两种交替活动:吃饭以及思考。当一个哲学家吃饭时,需要先拿起自己左右两边的两根筷子,并且一次只能拿起一根筷子。

____方案一:____下面是一种错误的解法,考虑到如果所有哲学家同时拿起左手边的筷子,那么就无法拿起右手边的筷子,造成死锁。

#define N 5 // 哲学家个数void philosopher(int i) // 哲学家编号:0 - 4{ while(TRUE) { think(); // 哲学家在思考 take_fork(i); // 去拿左边的叉子 take_fork((i + 1) % N); // 去拿右边的叉子 eat(); // 吃面条中…. put_fork(i); // 放下左边的叉子 put_fork((i + 1) % N); // 放下右边的叉子 }}

方案二:对拿叉子的过程进行了改进,但仍不正确

#define N 5 // 哲学家个数while(1) // 去拿两把叉子{ take_fork(i); // 去拿左边的叉子 if(fork((i+1)%N)) { // 右边叉子还在吗 take_fork((i + 1) % N);// 去拿右边的叉子 break; // 两把叉子均到手 } else { // 右边叉子已不在 put_fork(i); // 放下左边的叉子 wait_some_time(); // 等待一会儿 }}

方案三:等待时间随机变化。可行,但非万全之策

#define N 5 // 哲学家个数while(1) // 去拿两把叉子{ take_fork(i); // 去拿左边的叉子 if(fork((i+1)%N)) { // 右边叉子还在吗 take_fork((i + 1) % N);// 去拿右边的叉子 break; // 两把叉子均到手 } else { // 右边叉子已不在 put_fork(i); // 放下左边的叉子 wait_random_time( ); // 等待随机长时间 }}

方案四:互斥访问。正确,但每次只允许一人进餐

semaphore mute__ // 互斥信号量,初值1void philosopher(int i) // 哲学家编号i:0-4 { while(TRUE){ think(); // 哲学家在思考 P(mute__); // 进入临界区 take_fork(i); // 去拿左边的叉子 take_fork((i + 1) % N); // 去拿右边的叉子 eat(); // 吃面条中…. put_fork(i); // 放下左边的叉子 put_fork((i + 1) % N); // 放下右边的叉子 V(mute__); // 退出临界区 }}

正确方案如下:

为了防止死锁的发生,可以设置两个条件(临界资源):

必须同时拿起左右两根筷子;

只有在两个邻居都没有进餐的情况下才允许进餐。

必须由一个数据结构,来描述每个哲学家当前的状态#define N 5#define LEFT i // 左邻居#define RIGHT (i + 1) % N // 右邻居#define THINKING 0#define HUNGRY 1#define EATING 2typedef int semaphore;int state[N]; // 跟踪每个哲学家的状态 该状态是一个临界资源,对它的访问应该互斥地进行semaphore mute__ = 1; // 临界区的互斥 一个哲学家吃饱后,可能要唤醒邻居,存在着同步关系semaphore s[N]; // 每个哲学家一个信号量void philosopher(int i) { while(TRUE) { think(); take_two(i); eat(); put_tow(i); }}void take_two(int i) { P(&mute__); // 进入临界区 state[i] = HUNGRY; // 我饿了 test(i); // 试图拿两把叉子 V(&mute__); // 退出临界区 P(&s[i]); // 没有叉子便阻塞}void put_tow(i) { P(&mute__); state[i] = THINKING; test(LEFT); test(RIGHT); V(&mute__);}void test(i) { // 尝试拿起两把筷子 if(state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] !=EATING) { state[i] = EATING; V(&s[i]); // 通知第i个人可以吃饭了 }}

进程通信

进程同步与进程通信很容易混淆,它们的区别在于:

进程同步:控制多个进程按一定顺序执行

进程通信:进程间传输信息

进程通信是一种手段,而进程同步是一种目的。也可以说,为了能够达到进程同步的目的,需要让进程进行通信,传输一些进程同步所需要的信息。

__ 进程通信方式

直接通信

发送进程直接把消息发送给接收进程,并将它挂在接收进程的消息缓冲队列上,接收进程从消息缓冲队列中取得消息。

Send 和 Receive 原语的使用格式如下:

Send(Receiver,message);//发送一个消息message给接收进程ReceiverReceive(Sender,message);//接收Sender进程发送的消息message

间接通信

间接通信方式是指进程之间的通信需要通过作为共享数据结构的实体。该实体用来暂存发送进程发给目标进程的消息。

发送进程把消息发送到某个中间实体中,接收进程从中间实体中取得消息。这种中间实体一般称为信箱,这种通信方式又称为信箱通信方式。该通信方式广泛应用于计算机网络中,相应的通信系统称为电子邮件系统。

管道

管道是通过调用 pipe 函数创建的,fd[0] 用于读,fd[1] 用于写。

#include int pipe(int fd[2]);

它具有以下限制:

只支持半双工通信(单向传输);

只能在父子进程中使用。

命名管道

也称为命名管道,去除了管道只能在父子进程中使用的限制。

#include int mkfifo(const char __path, mode_t mode);int mkfifoat(int fd, const char __path, mode_t mode);

FIFO 常用于客户-服务器应用程序中,FIFO 用作汇聚点,在客户进程和服务器进程之间传递数据。

消息队列

间接(内核)

相比于 FIFO,消息队列具有以下优点:

消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;

避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;

读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。

信号量

它是一个计数器,用于为多个进程提供对共享数据对象的访问。

共享内存

允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是最快的一种 IPC。

需要使用信号量用来同步对共享存储的访问。

多个进程可以将同一个文件映射到它们的地址空间从而实现共享内存。另外 __SI 共享内存不是使用文件,而是使用使用内存的匿名段。

套接字

与其它通信机制不同的是,它可用于不同机器间的进程通信。

线程间通信和进程间通信

线程间通信

synchronized同步

这种方式,本质上就是 “共享内存” 式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。

while轮询的方式

在这种方式下,ThreadA 不断地改变条件,ThreadB 不停地通过 while 语句检测这个条件 (()==5) 是否成立 ,从而实现了线程间的通信。但是这种方式会浪费 CPU 资源。

之所以说它浪费资源,是因为 JVM 调度器将 CPU 交给 ThreadB 执行时,它没做啥 “有用” 的工作,只是在不断地测试某个条件是否成立。

就类似于现实生活中,某个人一直看着手机屏幕是否有电话来了,而不是:在干别的事情,当有电话来时,响铃通知TA电话来了。

wait/notify机制

当条件未满足时,ThreadA 调用 wait() 放弃 CPU,并进入阻塞状态。(不像 while 轮询那样占用 CPU)

当条件满足时,ThreadB 调用 notify() 通知线程 A,所谓通知线程 A,就是唤醒线程 A,并让它进入可运行状态。

管道通信

和 进行通信

进程间通信

管道(Pipe) :管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。

命名管道(named pipe) :命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。

信号(Signal) :信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;Linu__除了支持Uni__早期信号语义函数sigal外,还支持语义符合标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。

消息(Message)队列 :消息队列是消息的链接表,包括Posi__消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺

共享内存 :使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。

内存映射(mapped memory) :内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。

信号量(semaphore) :主要作为进程间以及同一进程不同线程之间的同步手段。

套接口(Socket) :更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Uni__系统的BSD分支开发出来的,但现在一般可以移植到其它类Uni__系统上:linu__和System V的变种都支持套接字。

进程操作

Linu__进程结构可由三部分组成:

代码段(程序)

数据段(数据)

堆栈段(控制块PCB)

进程控制块是进程存在的惟一标识,系统通过PCB的存在而感知进程的存在。系统通过 PCB 对进程进行管理和调度。PCB 包括创建进程、执行进程、退出进程以及改变进程的优先级等。

一般程序转换为进程分以下几个步骤:

内核将程序读入内存,为程序分配内存空间

内核为该进程分配进程标识符 PID 和其他所需资源

内核为进程保存 PID 及相应的状态信息,把进程放到运行队列中等待执行,程序转化为进程后可以被操作系统的调度程序调度执行了

在 UNI__ 里,除了进程 0(即 PID=0 的交换进程,Swapper Process)以外的所有进程都是由其他进程使用系统调用 fork 创建的,这里调用 fork 创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程 0 以外的进程都只有一个父进程,但一个进程可以有多个子进程。操作系统内核以进程标识符(Process Identifier,即 PID )来识别进程。进程 0 是系统引导时创建的一个特殊进程,在其调用 fork 创建出一个子进程(即 PID=1 的进程 1,又称 init)后,进程 0 就转为交换进程(有时也被称为空闲进程),而进程1(init进程)就是系统里其他所有进程的祖先。

进程0:Linu__引导中创建的第一个进程,完成加载系统后,演变为进程调度、交换及存储管理进程。进程1:init 进程,由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程。

Linu__中 1 号进程是由 0 号进程来创建的,因此必须要知道的是如何创建 0 号进程,由于在创建进程时,程序一直运行在内核态,而进程运行在用户态,因此创建 0 号进程涉及到特权级的变化,即从特权级 0 变到特权级 3,Linu__ 是通过模拟中断返回来实现特权级的变化以及创建 0 号进程,通过将 0 号进程的代码段选择子以及程序计数器EIP直接压入内核态堆栈,然后利用 iret 汇编指令中断返回跳转到 0 号进程运行。

创建一个进程

进程是系统中基本的执行单位。Linu__ 系统允许任何一个用户进程创建一个子进程,创建成功后,子进程存在于系统之中,并且独立于父进程。该子进程可以接受系统调度,可以得到分配的系统资源。系统也可以检测到子进程的存在,并且赋予它与父进程同样的权利。

Linu__系统下使用 fork() 函数创建一个子进程,其函数原型如下:

#include pid_t fork(void);

在讨论 fork() 函数之前,有必要先明确父进程和子进程两个概念。除了 0 号进程(该进程是系统自举时由系统创建的)以外,Linu__ 系统中的任何一个进程都是由其他进程创建的。创建新进程的进程,即调用 fork() 函数的进程就是父进程,而新创建的进程就是子进程。

fork() 函数不需要参数,返回值是一个进程标识符 (PID)。对于返回值,有以下 3 种情况:

对于父进程,fork() 函数返回新创建的子进程的 ID。

对于子进程,fork() 函数返回 0。由于系统的 0 号进程是内核进程,所以子进程的进程标识符不会是0,由此可以用来区别父进程和子进程。

如果创建出错,则 fork() 函数返回 -1。

fork() 函数会创建一个新的进程,并从内核中为此进程分配一个新的可用的进程标识符 (PID),之后,为这个新进程分配进程空间,并将父进程的进程空间中的内容复制到子进程的进程空间中,包括父进程的数据段和堆栈段,并且和父进程共享代码段(写时复制)。这时候,系统中又多了一个进程,这个进程和父进程一模一样,两个进程都要接受系统的调度。

注意:由于在复制时复制了父进程的堆栈段,所以两个进程都停留在了 fork() 函数中,等待返回。因此,fork() 函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。

下面给出的示例程序用来创建一个子进程,该程序在父进程和子进程中分别输出不同的内容。

#include #include #include int main(void){ pid_t pid; // 保存进程ID pid = fork(); // 创建一个新进程 if(pid < 0){ // fork出错 printf("fail to fork\n"); e__it(1); } else if(pid == 0){ // 子进程 // 打印子进程的进程ID printf("this is child, pid is : %u\n", getpid()); } else{ // 打印父进程和其子进程的进程ID printf("this is parent, pid is : %u, child-pid is : %u\n", getpid(), pid); } return 0;}

程序运行结果如下:

$ ./forkParent, PID: 2598, Sub-process PID: 2599Sub-process, PID: 2599, PPID: 2598

由于创建的新进程和父进程在系统看来是地位平等的两个进程,所以运行机会也是一样的,我们不能够对其执行先后顺序进行假设,先执行哪一个进程取决于系统的调度算法。如果想要指定运行的顺序,则需要执行额外的操作。正因为如此,程序在运行时并不能保证输出顺序和上面所描述的一致。

getpid() 是获得当前进程的pid,而 getppid() 则是获得父进程的 id。

父子进程的共享资源

子进程完全复制了父进程的地址空间的内容,包括堆栈段和数据段的内容。子进程并没有复制代码段,而是和父进程共用代码段。这样做是存在其合理依据的,因为子进程可能执行不同的流程,那么就会改变数据段和堆栈段,因此需要分开存储父子进程各自的数据段和堆栈段。但是代码段是只读的,不存在被修改的问题,因此这一个段可以让父子进程共享,以节省存储空间,如下图所示。

下面给出一个示例来说明这个问题。该程序定义了一个全局变量 global、一个局部变量 stack 和一个指针 heap。该指针用来指向一块动态分配的内存区域。之后,该程序创建一个子进程,在子进程中修改 global、stack 和动态分配的内存中变量的值。然后在父子进程中分别打印出这些变量的值。由于父子进程的运行顺序是不确定的,因此我们先让父进程额外休眠2秒,以保证子进程先运行。

#include #include #include // 全局变量,在数据段中int global;int main(){ pid_t pid; int stack = 1; // 局部变量,在栈中 int __ heap; heap = (int __)malloc(sizeof(int)); // 动态分配的内存,在堆中 __heap = 2; pid = fork(); // 创建一个子进程 if(pid < 0){ // 创建子进程失败 printf("fail to fork\n"); e__it(1); } else if(pid == 0){ // 子进程,改变各变量的值 global++; // 修改栈、堆和数据段 stack++; (__heap)++; printf("the child, data : %d, stack : %d, heap : %d\n", global, stack, __heap); e__it(0); // 子进程运行结束 } // 父进程休眠2秒钟,保证子进程先运行 sleep(2); // 输出结果 printf("the parent, data : %d, stack : %d, heap : %d\n", global, stack, __heap); return 0;}

程序运行效果如下:

$ ./forkIn sub-process, global: 2, stack: 2, heap: 3In parent-process, global: 1, stack: 1, heap: 2

由于父进程休眠了2秒钟,子进程先于父进程运行,因此会先在子进程中修改数据段和堆栈段中的内容。因此不难看出,子进程对这些数据段和堆栈段中内容的修改并不会影响到父进程的进程环境。

fork()函数的出错情况

有两种情况可能会导致fork()函数出错:

系统中已经有太多的进程存在了

调用fork()函数的用户进程太多了

一般情况下,系统都会对一个用户所创建的进程数加以限制。如果操作系统不对其加限制,那么恶意用户可以利用这一缺陷攻击系统。下面是一个利用进程的特性编写的一个病毒程序,该程序是一个死循环,在循环中不断调用fork()函数来创建子进程,直到系统中不能容纳如此多的进程而崩溃为止。下图展示了这种情况:

#include int main(){ while(1) fork(); /__ 不断地创建子进程,使系统中进程溢满 __/ return 0;}

创建共享空间的子进程

进程在创建一个新的子进程之后,子进程的地址空间完全和父进程分开。父子进程是两个独立的进程,接受系统调度和分配系统资源的机会均等,因此父进程和子进程更像是一对兄弟。如果父子进程共用父进程的地址空间,则子进程就不是独立于父进程的。

Linu__环境下提供了一个与 fork() 函数类似的函数,也可以用来创建一个子进程,只不过新进程与父进程共用父进程的地址空间,其函数原型如下:

#include pid_t vfork(void);

vfork() 和 fork() 函数的区别有以下两点:

vfork() 函数产生的子进程和父进程完全共享地址空间,包括代码段、数据段和堆栈段,子进程对这些共享资源所做的修改,可以影响到父进程。由此可知,vfork() 函数与其说是产生了一个进程,还不如说是产生了一个线程。

vfork() 函数产生的子进程一定比父进程先运行,也就是说父进程调用了 vfork() 函数后会等待子进程运行后再运行。

下面的示例程序用来验证以上两点。在子进程中,我们先让其休眠 2 秒以释放 CPU 控制权,在前面的 fork() 示例代码中我们已经知道这样会导致其他线程先运行,也就是说如果休眠后父进程先运行的话,则第 1 点则为假;否则为真。第 2 点为真,则会先执行子进程,那么全局变量便会被修改,如果第 1 点为真,那么后执行的父进程也会输出与子进程相同的内容。代码如下:

//@file vfork() usage#include #include #include int global = 1;int main(void){ pid_t pid; int stack = 1; int __heap; heap = (int __)malloc(sizeof(int)); ____eap = 1; pid = vfork(); if (pid < 0) { perror("fail to vfork"); ex___t(-1); } else if (pid == 0) { //sub-process, change values sleep(2);//release cpu controlling global = 999; stack = 888; ____eap = 777; //print all values printf("In sub-process, global: %d, stack: %d, heap: %d\n",global,stack,____eap); ex___t(0); } else { //parent-process printf("In parent-process, global: %d, stack: %d, heap: %d\n",global,stack,____eap); } return 0;}

程序运行效果如下:

$ ./vforkIn sub-process, global: 999, stack: 888, heap: 777In parent-process, global: 999, stack: 888, heap: 777

在函数内部调用vfork

在使用 vfork() 函数时应该注意不要在任何函数中调用 vfork() 函数。下面的示例是在一个非 main 函数中调用了 vfork() 函数。该程序定义了一个函数 f1(),该函数内部调用了 vfork() 函数。之后,又定义了一个函数 f2(),这个函数没有实际的意义,只是用来覆盖函数 f1() 调用时的栈帧。main 函数中先调用 f1() 函数,接着调用 f2() 函数。

#include #include #include int f1(void){ vfork(); return 0;}int f2(int a, int b){ return a+b;}int main(void){ int c; f1(); c = f2(1,2); printf("%d\n",c); return 0;}

程序运行效果如下:

$ ./vfork3Segmentation fault (core dumped)

通过上面的程序运行结果可以看出,一个进程运行正常,打印出了预期结果,而另一个进程似乎出了问题,发生了段错误。出现这种情况的原因可以用下图来分析一下:

左边这张图说明调用 vfork() 之后产生了一个子进程,并且和父进程共享堆栈段,两个进程都要从 f1() 函数返回。由于子进程先于父进程运行,所以子进程先从 f1() 函数中返回,并且调用 f2() 函数,其栈帧覆盖了原来 f1() 函数的栈帧。当子进程运行结束,父进程开始运行时,就出现了右图的情景,父进程需要从 f1() 函数返回,但是 f1() 函数的栈帧已经被 f2() 函数的所替代,因此就会出现父进程返回出错,发生段错误的情况。

由此可知,使用 vfork() 函数之后,子进程对父进程的影响是巨大的,其同步措施势在必行。

退出进程

当一个进程需要退出时,需要调用退出函数。Linu__ 环境下使用 e__it() 函数退出进程,其函数原型如下:

#include void e__it(int status);

e__it() 函数的参数表示进程的退出状态,这个状态的值是一个整型,保存在全局变量 $ ? 中,在 shell 中可以通过 echo $? 来检查退出状态值。

注意:这个退出函数会深入内核注销掉进程的内核数据结构,并且释放掉进程的资源。

e__it函数与内核函数的关系

e__it 函数是一个标准的库函数,其内部封装了 Linu__ 系统调用 e__it() 函数。两者的主要区别在于 e__it() 函数会在用户空间做一些善后工作,例如清理用户的 I/O 缓冲区,将其内容写入 磁盘文件等,之后才进入内核释放用户进程的地址空间;而 e__it() 函数直接进入内核释放用户进程的地址空间,所有用户空间的缓冲区内容都将丢失。

设置进程所有者

每个进程都有两个用户 ID,实际用户 ID 和有效用户 ID。通常这两个 ID 的值是相等的,其取值为进程所有者的用户 ID。但是,在有些场合需要改变进程的有效用户 ID。Linu__ 环境下使用 setuid() 函数改变一个进程的实际用户ID和有效用户ID,其函数原型如下:

#include int setuid(uid_t uid);

setuid() 函数的参数表示改变后的新用户 ID,如果成功修改当前进程的实际用户 ID 和有效用户 ID,函数返回值为 0;如果失败,则返回 -1。只有两种用户可以修改进程的实际用户 ID 和有效用户 ID:

根用户:根用户可以将进程的实际用户 ID 和有效用户 ID 更换。

其他用户:其该用户的用户 ID 等于进程的实际用户 ID 或者保存的用户 ID。

也就是说,用户可以将自己的有效用户 ID 改回去。这种情况多出现于下面的情况:一个进程需要具有某种权限,所以将其有效用户 ID 设置为具有这种权限的用户 ID,当进程不需要这种权限时,进程还原自己之前的有效用户 ID,使自己的权限复原。下面给出一个修改的示例:

#include #include #include int main(void){ FILE __fp; uid_t uid; uid_t euid; uid = getuid(); /__ 得到进程的实际用户ID __/ euid = geteuid(); /__ 得到进程的有效用户ID __/ printf("the uid is : %d\n", uid); printf("the euid is : %d\n", euid); if(setuid(8000) == -1){ /__ 改变进程的实际用户ID和有效用户ID __/ perror("fail to set uid"); e__it(1); } printf("after changing\n"); uid = getuid(); /__ 再次得到进程的实际用户ID __/ euid = geteuid(); /__ 再次得到进程的有效用户ID __/ printf("the uid is : %d\n", uid); printf("the euid is : %d\n", euid); return 0;}

程序运行效果如下:

$./setuidthe uid is : 0the euid is : 0after changingthe uid is : 8000the euid is : 8000

本节参考:

《后台开发:核心技术与应用实践》

《Linu__+C程序设计大全》十一章:进程控制

孤儿进程和僵尸进程

基本概念

我们知道在 Uni__/Linu__ 中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。当一个进程完成它的工作终止之后,它的父进程需要调用 wait() 或者 waitpid() 系统调用取得子进程的终止状态。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被 init 进程(进程号为1)所收养,并由 init 进程对它们完成状态收集工作____。____

僵尸进程:一个进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

问题及危害

Uni__ 提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息,就可以得到。这种机制就是:在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 the process ID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。但这样就导致了问题,如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。此即为僵尸进程的危害,应当避免。

孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了 init 进程身上,init 进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为 init,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

任何一个子进程(init除外)在e__it() 之后,并非马上就消失掉,而是留下一个称为僵尸进程 (Zombie) 的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在e__it()之后,父进程没有来得及处理,这时用 ps 命令就能看到子进程的状态是 Z。如果父进程能及时处理,可能用 ps 命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。如果父进程在子进程结束之前退出,则子进程将由 init 接管。init 将会以父进程的身份对僵尸状态的子进程进行处理。

僵尸进程危害场景:

例如有个进程,它定期的产生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程退出之后的事情,则一概不闻不问,这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用 ps 命令查看的话,就会看到很多状态为 Z 的进程。严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过 kill 发送 SIGTERM 或者 SIGKILL 信号啦)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被 init 进程接管,init 进程会 wait() 这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程就能瞑目而去了。

测试代码

孤儿进程测试程序如下所示:

#include #include #include #include int main(){ pid_t pid; //创建一个进程 pid = fork(); //创建失败 if (pid < 0) { perror("fork error:"); e__it(1); } //子进程 if (pid == 0) { printf("I am the child \n"); //输出进程ID和父进程ID printf("pid: %d\tppid:%d\n",getpid(),getppid()); printf("I will sleep five \n"); //睡眠5s,保证父进程先退出 sleep(5); printf("pid: %d\tppid:%d\n",getpid(),getppid()); printf("child process is \n"); } //父进程 else { printf("I am father \n"); //父进程睡眠1s,保证子进程输出进程id sleep(1); printf("father process is "); } return 0;}

僵尸进程测试程序如下所示:

#include #include #include #include int main(){ pid_t pid; pid = fork(); if (pid < 0) { perror("fork error:"); e__it(1); } else if (pid == 0) { printf("I am child am \n"); e__it(0); } printf("I am father will sleep two seconds\n"); //等待子进程先退出 sleep(2); //输出进程信息 system("ps -o pid,ppid,state,tty,command"); printf("father process is \n"); return 0;}

测试结果如下所示:

僵尸进程解决办法

通过信号机制

子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程

fork两次

将子进程成为孤儿进程,从而其的父进程变为 init 进程,通过 init 进程可以处理僵尸进程

守护进程

Linu__ Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linu__系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。

守护进程一般在系统启动时开始运行,除非强行终止,否则直到系统关机都保持运行。守护进程经常以超级用户(root)权限运行,因为它们要使用特殊的端口(1-1024)或访问某些特殊的资源。

一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程e__it退出了,所以它是一个由init继承的孤儿进程。守护进程是非交互式程序,没有控制终端,所以任何输出,无论是向标准输出设备stdout还是标准出错设备stderr的输出都需要特殊处理。

守护进程的名称通常以d结尾,比如sshd、__inetd、crond等

编写守护进程的一般步骤步骤:

在父进程中执行 fork 并 e__it 推出;

在子进程中调用 setsid 函数创建新的会话;

在子进程中调用 chdir 函数,让根目录 / 成为子进程的工作目录;

在子进程中调用umask函数,设置进程的umask 为 0;

在子进程中关闭任何不需要的文件描述符。

上下文切换

上下文切换,有时也称做进程切换或任务切换,是指CPU从一个进程或线程切换到另一个进程或线程。在操作系统中,CPU 切换到另一个进程需要保存当前进程的状态并恢复另一个进程的状态:当前运行任务转为就绪(或者挂起、删除)状态,另一个被选定的就绪任务成为当前任务

三、死锁

资源分类:(1)可重用资源;(2)消耗资源

什么是死锁

造成死锁的原因就是多个线程或进程对同一个资源的争抢或相互依赖。一个最简单的解释就是你去面试,面试官问你告诉我什么是死锁,我就录用你,你回答面试官你录用我,我告诉你。

如果一个进程集合里面的每个进程都在等待只能由这个集合中的其他一个进程(包括他自身)才能引发的事件,这种情况就是死锁。

这个定义可能有点拗口,下面用一个简单例子说明。

资源 A、B,进程 C、D 描述如下:

资源 A 和资源 B,都是不可剥夺资源,现在进程 C 已经申请了资源 A,进程 D 也申请了资源 B,进程 C 接下来的操作需要用到资源 B,而进程 D 恰好也在申请资源A,进程 C、D 都得不到接下来的资源,那么就引发了死锁。

然后套用回去定义:如果一个进程集合里面(进程 C 和进程 D)的每个进程(进程 C 和进程 D)都在等待只能由这个集合中的其他一个进程(对于进程 C,他在等进程 D;对于进程 D,他在等进程 C)才能引发的事件(释放相应资源)。

这里的资源包括了软的资源(代码块)和硬的资源(例如扫描仪)。资源一般可以分两种:可剥夺资源(Preemptable)和不可剥夺资源 (Nonpreemptable)。一般来说对于由可剥夺资源引起的死锁可以由系统的重新分配资源来解决,所以一般来说大家说的死锁都是由于不可剥夺资源所引起的。

死锁的必要条件

互斥:每个资源要么已经分配给了一个进程,要么就是可用的。

占有和等待:已经得到了某个资源的进程可以再请求新的资源。

不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。

循环等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。

死锁的处理方法

处理死锁的策略

鸵鸟策略

把头埋在沙子里,假装根本没发生问题。

因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。

大多数操作系统,包括 Uni__,Linu__ 和 Windows,处理死锁问题的办法仅仅是忽略它。

检测死锁并且恢复。

仔细地对资源进行动态分配,以避免死锁。

通过破除死锁四个必要条件之一,来防止死锁产生。

死锁检测与死锁恢复

不试图阻止死锁,而是当检测到死锁发生时,采取措施进行恢复。

(一)每种类型一个资源的死锁检测

上图为资源分配图,其中方框表示资源,圆圈表示进程。资源指向进程表示该资源已经分配给该进程,进程指向资源表示进程请求获取该资源。

图 a 可以抽取出环,如图 b,它满足了环路等待条件,因此会发生死锁。

每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。

(二)每种类型多个资源的死锁检测

上图中,有三个进程四个资源,每个数据代表的含义如下:

E 向量:资源总量

A 向量:资源剩余量

C 矩阵:每个进程所拥有的资源数量,每一行都代表一个进程拥有资源的数量

R 矩阵:每个进程请求的资源数量

进程 P1 和 P2 所请求的资源都得不到满足,只有进程 P3 可以,让 P3 执行,之后释放 P3 拥有的资源,此时 A = (2 2 2 0)。P2 可以执行,执行后释放 P2 拥有的资源,A = (4 2 2 1) 。P1 也可以执行。所有进程都可以顺利执行,没有死锁。

算法总结如下:

每个进程最开始时都不被标记,执行过程有可能被标记。当算法结束时,任何没有被标记的进程都是死锁进程。

寻找一个没有标记的进程 Pi,它所请求的资源小于等于 A。

如果找到了这样一个进程,那么将 C 矩阵的第 i 行向量加到 A 中,标记该进程,并转回 1。

如果没有这样一个进程,算法终止。

(三)死锁恢复

利用抢占恢复

利用回滚恢复

通过杀死进程恢复

死锁预防

在程序运行之前预防发生死锁,确保系统永远不会进入死锁状态。

(一)破坏互斥条件

例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进程。(把互斥地封装成可以同时访问的,例如:打印机的缓存)

(二)破坏占有和等待条件

一种实现方式是规定所有进程在开始执行前请求所需要的全部资源。

但是,这种策略也有如下缺点:

在许多情况下,一个进程在执行之前不可能知道它所需要的全部资源。这是由于进程在执行时是动态的,不可预测的;

资源利用率低。无论所分资源何时用到,一个进程只有在占有所需的全部资源后才能执行。即使有些资源最后才被该进程用到一次,但该进程在生存期间却一直占有它们,造成长期占着不用的状况。这显然是一种极大的资源浪费;

降低了进程的并发性。因为资源有限,又加上存在浪费,能分配到所需全部资源的进程个数就必然少了。

(三)破坏不可抢占条件

允许进程强行从占有者那里夺取某些资源。就是说,当一个进程已占有了某些资源,它又申请新的资源,但不能立即被满足时,它必须释放所占有的全部资源,以后再重新申请。它所释放的资源可以分配给其它进程。这就相当于该进程占有的资源被隐蔽地强占了。这种预防死锁的方法实现起来困难,会降低系统性能。

(四)破坏循环等待

实行资源有序分配策略。采用这种策略,即把资源事先分类编号,按号分配,使进程在申请,占用资源时不会形成环路。所有进程对资源的请求必须严格按资源序号递增的顺序提出。进程占用了小号资源,才能申请大号资源,就不会产生环路,从而预防了死锁。这种策略与前面的策略相比,资源的利用率和系统吞吐量都有很大提高,但是也存在以下缺点:

限制了进程对资源的请求,同时给系统中所有资源合理编号也是件困难事,并增加了系统开销;

为了遵循按编号申请的次序,暂不使用的资源也需要提前申请,从而增加了进程对资源的占用时间。

死锁避免

在程序运行时避免发生死锁,在使用前进行判断,只允许不会出现死锁的进程请求资源。

(一)安全状态

图 a 的第二列 Has 表示已拥有的资源数,第三列 Ma__ 表示总共需要的资源数,Free 表示还有可以使用的资源数。从图 a 开始出发,先让 B 拥有所需的所有资源(图 b),运行结束后释放 B,此时 Free 变为 5(图 c);接着以同样的方式运行 C 和 A,使得所有进程都能成功运行,因此可以称图 a 所示的状态时安全的。

定义:如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则称该状态是安全的。

安全状态的检测与死锁的检测类似,因为安全状态必须要求不能发生死锁。下面的银行家算法与死锁检测算法非常类似,可以结合着做参考对比。

(二)单个资源的银行家算法

一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。

不安全状态,因此算法会拒绝之前的请求,从而避免进入图 c 中的状态。

(三)多个资源的银行家算法

有五个进程,四个资源。左边的图表示已经分配的资源,右边的图表示还需要分配的资源。最右边的 E、P 以及 A 分别表示:总资源、已分配资源以及可用资源,注意这三个为向量,而不是具体数值,例如 A=(1020),表示 4 个资源分别还剩下 1/0/2/0。

检查一个状态是否安全的算法如下:

查找右边的矩阵是否存在一行小于等于向量 A。如果不存在这样的行,那么系统将会发生死锁,状态是不安全的。

假若找到这样一行,将该进程标记为终止,并将其已分配资源加到 A 中。

重复以上两步,直到所有进程都标记为终止,则状态时安全的。

如果一个状态不是安全的,需要拒绝进入这个状态。

如何在写程序的时候就避免死锁

所谓的死锁呢,发生的主要原因在于了有多个进程去竞争资源,也就是同时去抢占。

可以自己写一个支持多线程的消息管理类,单开一个线程访问独占资源,其它线程用消息交互实现间接访问。这种机制适应性强、效率高,更适合多核环境。

四、内存管理

虚拟内存

虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。

为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到一部分不在物理内存中的地址空间时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。

从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序称为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。

分页系统地址映射

内存管理单元(MMU):管理着地址空间和物理内存的转换。

页表(Page table):页(地址空间)和页框(物理内存空间)的映射表。例如下图中,页表的第 0 个表项为 010,表示第 0 个页映射到第 2 个页框。页表项的最后一位用来标记页是否在内存中。

下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。因此对于虚拟地址(0010 000000000100),前 4 位是用来存储页面号,而后 12 位存储在页中的偏移量。

(0010 000000000100)根据前 4 位得到页号为 2,读取表项内容为(110 1),它的前 3 为为页框号,最后 1 位表示该页在内存中。最后映射得到物理内存地址为(110 000000000100)。

页面置换算法

在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。

页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

最佳

Optimal

所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。

是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。

举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:

开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。

最近最久未使用

LRU, Least Recently Used

虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。

为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面时最近最久未访问的。

因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。

最近未使用

NRU, Not Recently Used

每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类:

R=0,M=0

R=0,M=1

R=1,M=0

R=1,M=1

当发生缺页中断时,NRU 算法随机地从类编号最小的非空类中挑选一个页面将它换出。

NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁使用的干净页面(R=1,M=0)。

先进先出

FIFO, First In First Out

选择换出的页面是最先进入的页面。

该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。

第二次机会算法

FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:

当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。

时钟

Clock

第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面链接起来,再使用一个指针指向最老的页面。

分段

虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。

下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。

分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。

段页式

程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。

分页与分段的比较

对程序员的透明性:分页透明,但是分段需要程序员显示划分每个段。

地址空间的维度:分页是一维地址空间,分段是二维的。

大小是否可以改变:页的大小不可变,段的大小可以动态改变。

出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。

五、设备管理

磁盘结构

盘面(Platter):一个磁盘有多个盘面;

磁道(Track):盘面上的圆形带状区域,一个盘面可以有多个磁道;

扇区(Track Sector):磁道上的一个弧段,一个磁道可以有多个扇区,它是最小的物理储存单位,目前主要有 512 bytes 与 4 K 两种大小;

磁头(Head):与盘面非常接近,能够将盘面上的磁场转换为电信号(读),或者将电信号转换为盘面的磁场(写);

制动手臂(Actuator arm):用于在磁道之间移动磁头;

主轴(Spindle):使整个盘面转动。

磁盘调度算法

读写一个磁盘块的时间的影响因素有:

旋转时间(主轴旋转磁盘,使得磁头移动到适当的扇区上)

寻道时间(制动手臂移动,使得磁头移动到适当的磁道上)

实际的数据传输时间

其中,寻道时间最长,因此磁盘调度的主要目标是使磁盘的平均寻道时间最短。

先来先服务

FCFS, First Come First Served

按照磁盘请求的顺序进行调度

公平对待所有进程

在有很多进程的情况下,接近随机调度的性能

优点是公平和简单。缺点也很明显,因为未对寻道做任何优化,使平均寻道时间可能较长。

最短寻道时间优先

SSTF, Shortest Seek Time First

优先调度与当前磁头所在磁道距离最近的磁道。

虽然平均寻道时间比较低,但是不够公平。如果新到达的磁道请求总是比一个在等待的磁道请求近,那么在等待的磁道请求会一直等待下去,也就是出现饥饿现象。具体来说,两边的磁道请求更容易出现饥饿现象。

电梯算法

SCAN

电梯总是保持一个方向运行,直到该方向没有请求为止,然后改变运行方向。

电梯算法(扫描算法)和电梯的运行过程类似,总是按一个方向来进行磁盘调度,直到该方向上没有未完成的磁盘请求,然后改变方向。

因为考虑了移动方向,因此所有的磁盘请求都会被满足,解决了 SSTF 的饥饿问题。

六、链接

编译系统

以下是一个 程序:

#include int main(){ printf("hello, world\n"); return 0;}

在 Uni__ 系统上,由编译器把源文件转换为目标文件。

gcc -o hello

这个过程大致如下:

预处理阶段 (Preprocessing phase)

预处理(cpp)根据以字符 # 开头的命令,修改原始的 C 程序,生成扩展名为 .i 的文件。

$ gcc -E -o

编译阶段 (Compilation phase)

编译器(cc1)将文本文件 翻译成文本文件 ,它包含一个汇编语言程序。

$ gcc -S -o

汇编阶段 (Assembly phase)

编译器(as)将 翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件 中。

$ as -o

链接阶段 (Linking phase)

printf 函数是标准 C 库中的一个函数,在 这个单独预编译好的目标文件中。连接器(ld)将 和 合并,结果得到 hello 可执行目标文件。

$ gcc -o hello

静态链接

静态连接器以一组可重定向目标文件为输入,生成一个完全链接的可执行目标文件作为输出。链接器主要完成以下两个任务:

符号解析:每个符号对应于一个函数、一个全局变量或一个静态变量,符号解析的目的是将每个符号引用与一个符号定义关联起来。

重定位:链接器通过把每个符号定义与一个内存位置关联起来,然后修改所有对这些符号的引用,使得它们指向这个内存位置。

目标文件

可执行目标文件:可以直接在内存中执行;

可重定向目标文件:可与其它可重定向目标文件在链接阶段合并,创建一个可执行目标文件;

共享目标文件:这是一种特殊的可重定向目标文件,可以在运行时被动态加载进内存并链接;

动态链接

静态库有以下两个问题:

当静态库更新时那么整个程序都要重新进行链接;

对于 printf 这种标准函数库,如果每个程序都要有代码,这会极大浪费资源。

共享库是为了解决静态库的这两个问题而设计的,在 Linu__ 系统中通常用 .so 后缀来表示,Windows 系统上它们被称为 DLL。它具有以下特点:

在给定的文件系统中一个库只有一个文件,所有引用该库的可执行目标文件都共享这个文件,它不会被复制到引用它的可执行文件中;

在内存中,一个共享库的 .te__t 节(已编译程序的机器代码)的一个副本可以被不同的正在运行的进程共享。

操作系统基础知识大全 第8篇

熟读DCS操作手册

一、规程术语含义

注意:表示涉及的事物或操作可能引起不可预测的危险后果。

警告:表示涉及的事物或操作能引起可预见的系统运行故障。

危险:表示涉及的事物或操作将引起系统停运,甚至设备损坏及人身伤害。

二、操作员操作职责

1、监视DCS系统运行,预防可能产生的危险。

2、随时干预系统运行,确保安全、正常生产。

3、系统授权运行参数的更改。

三、系统异常情况处理

1、DCS操作界面数据不刷新(正常情况数据每秒刷新一次),手自动切换无法操作等情况,应联系DCS 维护人员进行维护,同时立即到现场操作。

2、出现变送器故障,自动控制过程应立即切回手动。

3、出现阀门执行机构,回路输出卡件等故障现象,应改为现场操作。

4、出现DCS系统回路输入卡件故障时应把相应控制回路切回手动,并更换故障卡件,检查确认故障 消除后方可再次投入自动。

5、DCS系统出现异常断电,应改为现场操作。重新上电后,要求工程师检查系统情况,检查回路参 数等系统数据是否正常,确认各调节阀的开度。若有异常应重新下传组态,一切正常后方可再次投入自动。

6、其他异常情况请参照岗位操作规程执行。

四、报警处理

工艺指标产生报警时会有声音提示,报警信息在报警信息栏和报警一览画面中指示,报警情况了解后,用消音按钮关闭当前的报警声音,分析报警原因后采取相应的操作。

五、检测控制点

随时密切监视与控制息息相关温度、压力、液位、电流、阀位等。

六、调节阀控制

系统工程师(工程师以上)职责

1、系统软、硬件维护。

2、 DCS系统的启动和停止。

3、操作员口令的设臵与修改。

4、系统重要运行参数的维护与修改。

5、其它涉及系统的职责。

6、注意事项:

▼当系统出现停电时,应立即将系统中投入自动控制的回路切到手动。当供电正常时,首先检 查系统运行及系统数据是否正常,如果有异常现象,重新下传组态,并检查核对系统参数。一切正常后方可再次投入自动。(参数表参见相关资料)

▼统启动运行上电顺序:UPS、控制站、显示器、操作站计算机。

▼停机次序:控制站计算机、显示器、控制站、UPS。

▼操作员口令维护:每台操作站上的操作员口令之间无任何关系,必须单独建立。口令是保证系 统安全正常运行的前提,必须严格执行。

▼历史数据保存在操作站硬盘上,与系统停电等因素无关。历史数据是追查事故责任的重要手段。

▼操作站计算机是系统的重要组成部分,必须保持其正常运行和整洁。

▼当系统卡件故障时应把相应控制回路立即切回手动,并通知DCS系统维护人员立即更换故障卡件,检查确认故障消除时方可再次将系统投入自动。

七、操作员职责

1、监视DCS系统运行,预防可能产生的危险。

2、随时干预系统运行,确保安全、正常生产。

3、系统授权运行参数的更改。

4、自动控制投运方法:将画面中的回路仪表的手/自动开关打到自动即可。

5、报警处理:工艺指标产生报警时会有声音提示,报警信息在报警信息栏和报警一览画面中指示, 报警情况了解后,用消音按钮关闭当前的报警声音,并在报警一览中确认。

6、异常情况处理:

▼自动控制过程中,出现变送器故障,应立即切回手动。

▼如果出现阀门故障现象,此时应切回手动,改为现场操作。

▼系统出现断电,此时应立即切回手动,并要求工程师检查系统情况,确认完好后方可再次投 入自动。

▼DCS操作界面数据不刷新(正常情况数据每秒刷新一次),手自动切换无法操作等情况,应联 系仪表人员进行维护。同时立即到现场操作。

▼出现系统卡件故障时应把相应控制回路切回手动,并由仪表人员更换故障卡件,检查确认故 障消除后方可再次投入自动。

▼DCS系统出现异常断电,应改为手动操作。重新上电后,要求工程师检查系统情况,检查回 路参数等系统数据是否正常,确认各调节阀的开度。一切正常后方可再次投入自动。

DCS系统一旦出现故障,如何用最短时间准确诊断故障?

看工经典案例

Q1:哪些情况是控制系统问题还是工艺问题?

A:出现以下情况时,说明控制系统发生问题,应立即通知微机维修人员维修,同时操作工到现场进行处理。

1、 经常变化的数据长时间不变,且几个数据或所有数据都不变。

2、 控制分组画面中,手动自动无法切换,或手动输入数据后,一经确认,又恢复为原来的数据,修改不过来。

3、 趋势图画面中,几条趋势都为直线不变。

4、 监控画面中,多个数据同时波动较大。

判断波动数据是否为工艺上相关参数,若是相关参数则通知仪表及微机人员检查,看是否某调节系统波动引起相关参数变化,同时将相关调节系统打到手动状态,必 要时到现场进行调节。

若波动数据工艺上彼此并无直接影响,则可能为微机某卡件发生故障,立即将相关自调系统打到手动调节,必要时到现场进行调节,同时,通知微机及仪表人员检查。

Q2:大修后DCS系统如何上电,如何对DCS供电检查?

A:DCS系统对供电质量有一定要求,大修后DCS上电应注意:

1、确认外部供电是否平稳,如检修期间电压不稳不要上电。

2、测试外部供电电压是否符合198V-242V要求。

3、上电时按先总电源,再操作站,控制柜,外配柜顺序上电(断电则相反)。

4、上电后对DCS卡件故障报警、电压故障报警、交换机和网络检查,对供电电压测试。

5、用万用表可检查DCS每个机笼的5V、24V电压,如低于5V、24V则不正常。如需对供电质量深入检查,需用示波器或电能质量分析仪检测分析。

专家建议:系统维护负责人确认条件具备方可上电。应严格遵照上电步骤进行。

Q3:中控室日常管理应注意些什么?

A:控制室的日常管理对系统稳定运行和维护很重要,日常管理应注意:

1)、控制室门窗位置布置合理,操作站、控制柜、UPS放置规范,标识清楚。

2)、控制室保持日常清洁,维持适当的温度和湿度,检查照明、空调运行情况。

3)、检查系统防水、防尘、防腐蚀和防振情况,日常发现有漏洞的地方及时整改。

4)、规范管理,不允许无关人员触碰控制柜卡件,对操作站设置密码,加强保密安全管理。

5)、对控制柜内开关、端子、外配等部件标识检查,使之标识清晰方便维护。

专家建议:控制室温度范围0-50摄氏度,20度左右适宜;湿度范围:10%-90%RH,无凝露。

Q4:DCS系统在日常维护时如何能了解到系统当前故障情况?

A:日常维护时注意观察很重要,重点观察了解的地方为:

1、控制站卡件指示等显示是否异常(fail灯是否亮红灯),

2、进入监控“故障诊断”画面查看是否有卡件运行故障提示、通讯网络异常提示,

3、检查系统供电是否正常。

4、检查控制站电源风扇是否运行,交换机指示灯是否正常,是否有腐蚀现象(接线头或机柜铜条处是否发黑等现象)。

Q5:如何简单检查DCS系统接地?

DCS系统的接地示意图

A:DCS接地是一个很复杂的问题,涉及到接地地点,接地方式,接地电阻大小等从现场到DCS机柜的诸多节点和环节。但日常对DCS的常规检查主要有几个方面:

1、DCS机柜应采用单点接地方式,检查是否有可能导致多点接地的地方出现,比如机柜与槽钢的接触,接地点是否为单条引下线(线径大于16mm2,长度小于30米)到地桩或地网,部件连接(或焊接)点是否良好(锈蚀)等。

2、检查DCS接地点与电气地或避雷针引下线接地是否共用,距离是否符合要求,一般情况要求DCS接地与电气地距离15米以上,与避雷针接地点15米以上。

3、测量DCS系统接地电阻是否小于4欧姆。接地电阻的大小与很多因素相关,如接触良好,土壤湿度,导电率等,测量接地电阻可选用的仪器有摇表、钳形表等。

Q6:日常维护时如何检查DCS系统网络?

A:1、用网络测试仪测试网线硬件是否正常,检查交换机指示灯是否正常。

2、检查监控“故障诊断”画面是否有故障提示。

3、对每台计算机使用“ping”命令检查网络是否正常,IP设置是否正确。

4、检查网卡流控制是否关闭,网卡驱动安装是否正常。

5、使用组态软件自带SCDIAGNOSE软件检测网络情况。

Q7:DCS系统维护如何做好防静电?

A:如果维护不注意,静电可能对DCS卡件或通讯带来不小影响,DCS维护过程中特别是在触碰硬件卡件或通讯部件时应采取如下措施做好防静电。

1、保持环境有一定的湿度。特别北方地区或在干燥的冬季,因静电产生故障的事例要远远大于在东南沿海地区或其他季节,所以在一些重要场所,如计算机机房、实验室、电子仪器的装调车间应考虑保持一定湿度的问题,特别是对那些封闭形的空调房间,更应有一定控制湿度的设备。

2、铺设防静电地板,控制室和操作室均需铺设防静电地板。

3、在维护插扒卡件时或用手拿捏卡件时一定注意先对手释放静电,注意尽量避免用手直接触碰卡件电子元件、面板电路和焊点。

4、卡件应存放在防静电塑料盛放器或防静电塑料袋中,并存放在卡件盒中。

5、系统维护时还应注意佩带DCS防静电手腕。

Q8:DCS日常维护时需要对哪些数据进行备份?

A:需要对组态、PID参数、工艺参数(设定值)、系统安装软件、电脑驱动以及认为重要的趋势、报表等数据进行备份。

Q9:DCS系统某测点信号(温度、压力或流量等)显示故障应如何快速排除?

A:信号显示数据不准或无显示是可能常遇到的问题,它可能由于现场仪表引起,也可能由于DCS引起,可采取快速判断的方法有:

1、用信号发生器模拟标准信号测试(前提是现场必须有信号发生器可使用)或将另一同类型信号线缆改接到该通道信号引入测试,若正常表明DCS正常,再检查现场进DCS信号是否有误。

2、检查信号线正负是否接反、卡件跳线设置是否正确(特别是新增点),组态型号、量程、补偿等参数设置是否有误。

3、检查该信号所属卡件其他测点运行是否正常,并根据现场实际情况判断是否可采用对该卡件备件更换的方式检测是否为卡件故障,更换时注意跳线设置。

Q10:某操作站监控有时候会自动退出,是否异常?

A:系统退出的原因有很多,几个月偶尔退出1次,属于系统正常情况,因为如果计算机内存占用过大或运行程序过多有可能影响监控退出。但如果频繁退出(比如每天或每周)则不正常。一般系统退出主要有如下几种原因:

1、系统软件安装不规范,重新安装后可以解决。

2、同一个时间恰好出现了多个报警,导致计算机系统的资源不足报错。

3、系统调用的组态路径为网络路径,非本机路径。

4、硬件如主板或硬盘出现故障。

5、若硬盘空间不够,也可能自动退出。

Q11:计算机重启后异常?

A:用户现场使用DELL液晶显示器,操作系统为WIN NT。某次重启操作系统后,无法正常进入桌面,提示不支持vga格式。与维护人员交流,在重启计算机前做过何种操作,反馈为提高了显示器的分辨率。判断可能是调高了分辨率后导致NT系统自检时无法识别显示系统。进入BIOS,恢复系统默认设置后系统恢复正常。

Q12:操作员键盘为何会引起死机?

A:原因分析:键盘外壳未良好接地,人体静电对键盘的冲击,也会导致键盘死机。

解决方案:

1、新键盘外壳生产时,要求外协单位在键盘上留出接地孔或接地杆;

2、安装时,使键盘外壳与键盘线屏蔽地可靠连接;

3、键盘外壳上去除部分涂层,使外壳有有效接地点。

Q13:压力信号异常是何原因?

A:压力信号出现满量程情况,与实际不符。断开卡件后面的信号线正极,信号由满量程变仍有8公斤左右压力信号(量程为0-13公斤)。经现场观察,该测点经过安全栅。将信号线短路,不过安全栅后,信号显示正常。

初步判断是安全栅出现问题。原因可能是同一组的信号,安全栅是共地的。当安全栅故障后,另一毫安信号耦合到该信号上来,造成信号的干扰。

Q14:热电阻信号不准如何排查?

A:首先,检查热电阻的组态,确认了组态中的热电阻型号和实际的型号保持一致;其次,确保上下位机组态一致。最后,如果还是怀疑测温有问题的话,可以测量现场热电阻A和B之间的阻值为R1;B和C之间的阻值为R2。

根据3线制热电阻的测温原理,可以得到热电阻的实际电阻值为R1-2R2。然后查表找出对应的温度。然后用这个温度和监控上的温度再进行比较。如果出入较大,请更换卡件后再次尝试。

Q15:如何快速排查系统通讯故障?

A:在系统运行过程中若发现通讯故障,应重点做如下检查:

1、了解清楚具体故障现象,是所有通讯中断还是某部分数据通 讯异常,还是某操作站通讯异常,这对之后的排查很重要。

2、工程师权限进入监控故障诊断画面,观察是否有通讯卡件或总线故障报警(如数据转发卡,主控卡等)提示。发现卡件故障用备件更换。

3、检查目前网络是否通畅,检查交换机、控制站供电是否正常。可用计算机ping命令检查各网络节点是否通畅。

4、网线、交换机、SBUS线等故障均可能引起网络故障,可将其排除法更换测试。

5、检查有问题操作站IP设置是否正确,卡件地址(主控卡、数据转发卡)设置是否正确、网卡驱动是否正确安装,网线连接是否不正确(交叉等)。

操作系统基础知识大全 第9篇

一、操作系统相关概念

计算机软件:系统软件和应用软件。

计算机系统资源:硬件资源、软件资源。

硬件资源:中央处理器、存储器、输入、输出等物理设备。

软件资源:以文件形式保存到存储器上的程序和数据信息。

定义:有效地组织和管理系统的各种软/硬件资源,合理组织计算机系统工作流程,控制程序的执行,并给用户提供一个良好的环境和友好的接口。

操作系统作用:通过资源管理提高计算机系统的效率、改善人家界面提高良好的工作环境。

吞吐量:计算机在单位时间内处理工作的能力。

二、操作系统的特征与功能

操作系统的特征:并发性、共享性、虚拟性、随机性。

、 操作系统的功能

1、进程管理:实际上是对处理机的执行时间进行管理,采用多道程序等技术将CPU的时间合理分配给每个任务。比如:进程控制、进程同步、进程通信、进程调度。

2、文件管理:主要有存储空间管理、目录管理、文件读写。

3、存储管理:对主存储器空间进行管理,主要包括存储空间分配回收、存储保护、地址映射、主存扩充等。

4、设备管理:对硬件设备的管理。包括分配、启动、完成、回收。

5、作业管理:包括任务、界面管理、人机交互、语音控制、虚拟现实等。

三、操作系统分类

1、批处理操作系统

分为单道批处理、多道批处理。

单道批处理:早期的操作系统,一次只有一个作业装入内存执行。作业由用户程序、数据和作业说明书组成。一个作业运行结束后,自动调入同批的下一个作业。

多道批处理:允许多个作业装入内存执行,在任意时刻,作业都处于开始和结束点之间。

多道批处理系统特点:多道、宏观上并行运行、微观上串行运行。

2、分时操作系统

分时操作系统是将CPU的工作划分为很短的时间片。轮流为各个终端的用户服务。

分时操作系统特点:多路性、独立性、交互性、及时性。

3、实时操作系统

实时操作系统对交互能力要求不高,要能对外来信息足够快的速度响应和处理。分为实时控制系统和实时信息处理系统。

实时控制系统:主要用于生产过程的自动控制,比如自动采集、飞机的自动驾驶等。

实时信息处理系统:主要是实时信息处理,比如飞机订票系统、情报检索系统等。

4、网络操作系统

网络操作系统使互联网能方便有效的共享网络资源,为网络用户提供各种服务软件和有关协议的几何。比如电子邮件、文件传输、共享硬盘等。

网络操作系统分为如下三类:

1、集中式:系统的基本单元由一台主机和若干台主机相连的终端构成,将多台主机连接处理形成网络。比如UNI__。

2、客户端/服务器模式:该模式分为客户端和服务器。服务器是网络控制的中心,向客户端提供多种服务,客户端主要是访问服务端的资源。

3、对等模式(P2P):相当于每一台客户端都可以给其他客户端提供资源服务。

5、分布式操作系统

分布式操作系统是由多个分散的计算机经连接而成的计算机系统,系统中的计算机无主次之分,任意两台计算机都可以交换信息。分布式操作系统能直接对各类资源进行动态分配和调度、任务划分、信息传输协调工作,为用户提供一个统一的界面、标准的接口,用户通过这一界面实现所需要的操作和使用系统资源。

6、微机操作系统

目前主流的操作系统有Linu__、MacOS、Windows。

7、嵌入式操作系统

嵌入式操作系统运行在嵌入式智能芯片环境中,对整个智能芯片以及操作、控制、部件装置等资源进行统一协调、处理、指挥、控制。

嵌入式操作系统特点:微型化、可定制、实时性、可靠性、易移植性。

操作系统基础知识大全 第10篇

1、经常进行“磁盘清理”和磁盘碎片整理”

当硬盘用久了,无数次的新增、更改和删除程序和文件后,就会造成很多断断续续的扇区,非连续性的文件便会愈来愈多,硬盘磁头便需要花更多时间跳来跳去来读取数据,这就导致硬盘速度减慢。

因此,我们应该定期进行“磁盘清理”和磁盘碎片整理”,将所有非连续性的文件重新编排整齐。

处理方法:点开始-程序-附件-系统工具-磁盘清理程序和磁盘碎片整理程序。有可能整理过程很慢,那是你长时间没有清理或者有只读文件,请多执行几次,耐心等待。碎片清理时要退出所有的应用程序。

2、移动internet临时文件和临时交换文件

internet临时文件和临时交换文件是我们上网时产生的临时文件,是产生磁盘碎片的罪魁祸首,叫它离开系统盘是最好的办法处理方法:

⑴在桌面上右键点internet e__plorer图标,再点出来的“属性”,出属性对话框,在internet临时文件后面点“设置”,在出来的设置对话框中点移动文件夹,再选择除系统盘以外的硬盘(如D盘);

⑵、开始-设置-控制面板-双击系统,在“性能”项上点“设置”,在“性能选项”上点“高级”,在“虚拟内存”选项点“更改”,选择除系统盘外的硬盘如d,最后确定。关机重启,ok。

3、开启wondows __p保留的20%带宽

wondows __p默认保留了20%的带宽,我们可以将它开启,充分利用带宽。处理方法:点开始-运行,输入,打开组策略-计算机配置—管理模板—网络—Qos数据包调度程序,右击窗口右边的“限制可保留带宽”选项,单击“属性”命令,在弹出的“限制可保留带宽属性”对话框中的“设置”选项卡中,勾选“已启用”单选框,将下面的“带宽限制”数值调到“0”。点确定,ok。

4、删除不必要的系统声音

系统声音是计算机事件的一组声音方案,实际一点用处没有,还占用一部分系统内存,干掉它是明智的选择。

处理方法:右键点通知栏里的小喇叭,点调整音频属性,在属性框中点声音,点方案后面的“删除”,再确定,ok。

5、定期清理internet预读文件

在聊天室碰到好多次有些朋友突然打不开我们聊天室的网页了,而其他的网站可以。问题是出现了死连接,实际__P使用一段时间后,预读文件夹里的文件会变得很大,里面会有死链文件,这会减慢系统时间。建议:定期删除。

处理方法:在桌面上右键点internet e__plorer图标,再点“属性”,出属性对话框,在internet临时文件后面点“删除cookies”、“删除文件”。

提醒:删除文件时请选择“删除所有脱机文件”。

6、关于internet e__plorer

IE并不是最佳的浏览器,其缺点之一是占用太多的系统资源,第一次开启IE,占用7%左右的资源,以后每开启一个IE窗口,占用4%左右的资源。现在上网,网页自身自动开启的弹出式窗口就多,快速消耗你的内存是很自然的事情,CUP使用率常在100%也不奇怪。

7、优化硬盘参数

右击“我的电脑”,选“属性”,选中“硬件”下的“设备管理器”标签,然后在“磁盘驱动器”中找到你的硬盘,查看它的属性,在“磁盘属性”标签中选中“启用了写入缓存”;在“IDE控制器”中分别查看“Primary IDE Channel”和“Secondary IDE Channel”的属性,在“高级设置”中将“设备类型”设定为“自动检测”,“传输模式”设定为“DMA(若可用)”。

8、让系统自动释放系统资源

在Windows中每运行一个程序,系统资源就会减少。即使把程序关闭,在内存中还有一些没用的.DLL文件在运行,这样就使得系统的运行速度下降。可以通过修改注册表,令程序关闭后自动清除没有用的DLL文件,收回系统资源。

处理方法:运行regedit打开注册表编辑器,找到并选中HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrenVersione__plorer主键,在右边窗格单击右键,新建一个字符串值,名为AlwaysUnloadDll,然后将AlwaysUnloadDll的键值改为1,退出注册表,重启计算机。

9、固定自己的DNS和IP

一般__P/20XX是自动检测IP和DNS地址的,但我们可以自己设置好,以提高系统效率,前提是你要与服务商联系,获取你的DNS和IP地址。处理方法:点开始-设置-控制面板-双击网络连接,点方框中TCP/IP,点属性,点IP地址,选择“指定IP地址”,填入你从服务商那里得到的IP地址和子关掩码;点DNS配置,选择“启用DNS",填入你得到的服务器地址,添加。

10、关于ADSL猫的使用注意事项

因为猫对电源的要求实际很高,只是我们不太注意,猫的电源应该尽量采用独立的电源线,中间要注意避开大功率的用电设备,防止其他用电设备对它的干扰,采取一定的屏蔽接地措施是明智的。

另外注意选择品牌大的猫并注意与服务商提供服务的兼容性,如果ISP的局端设备有了改动,这时我们可能会经常掉线,这时建议下载Firmware版本刷新程序对“大猫”刷新,一般可以完全解决。再者使猫保持良好的散热效果,最好将猫的下面垫空。

操作系统基础知识大全 第11篇

1、计算机作业的概念

计算机中的作业是为了完成某个用户的计算任务所做工作的总和。

作业管理程序:操作系统中用来控制作业进入、执行、撤销的一组程序。

2、作业与作业的控制方式

脱机控制方式:用户需要把自己需要计算机完成的任务用作业控制语言编写成作业说明书,连同作业一并交给操作系统。作业的执行过程是不需要人为干预的。

联机控制方式:操作系统向用户提供一组联机命令,用户通过 终端输入命令将自己需要计算机干什么的意图高速计算机,用来控制作业的运行过程,这个是需要人机交互配合的。

作业的组成:程序、数据、作业说明书。

作业说明书组成:作业基本情况、作业控制、作业资源要求描述。

作业基本情况:用户名、作业名、编程语言、最大处理时间。

作业控制描述:作业控制方式、作业步骤的操作顺序、作业执行出错处理

作业资源要求描述:处理时间、优先级、主存空间、外设类型、数量。

3、作业状态及转换

1、提交:通过输入设备送入计算机系统的过程状态称为提交状态。

2、后备:通过Spooling系统将作业输入到计算机系统的后备存储器中、随时等待作业调度程序调度时的状态。

3、执行:当作业被作业调度程序选中,为其分配需要的资源、并建立相应的进程后,作业就进入了执行状态。

4、完成:作业正常结束或异常终止时,作业就会进入完成状态。作业调度程序会对该作业进行后续处理,比如撤销作业的控制块、回收作业占用的系统资源等。

4、作业控制块和作业后备队列

作业控制块(JCB):记录与该作业有关的各种信息的登记表。它是作业的唯一标识,包括用户名、作业名、状态标志等信息。

作业后备队列:作业控制块排成一个或多个队列称为作业后备对了。是由若干个JCB组成的。

5、作业调度

作业调度算法:

1、先来先到:按照作业到达的先后进行调度。优先启动等待时间最长的作业。

2、短作业有限:优先运行时间最短的的作业。

3、响应比高优先:响应比高的作业优先启动。

公式:R=作业响应时间/作业执行时间

作业响应时间为作业进入系统后的等候时间与作业的执行时间之和。R=1+(作业等待时间)/作业执行时间

特点:算法负责,系统开销大。

4、优先级调度算法:由用户指定作业优先级,优先级高的作业先启动。也可以由系统根据作业要求的紧迫程度决定优先启动。

5、均衡调度算法:根据系统的运行情况和作业本身的特性对作业进行分类。作业调度程序轮流地从这些不同类别的作业挑选对应的作业执行。

6、作业调度算法性能的衡量指标

在批处理为主的系统中,通常用平均周转时间或平均带权周转时间来衡量调度性能的优劣。

推荐访问:

相关推荐

热门文章

2024年浅谈纪检监察工作面临困难及对策

民主政治是实施权力监督的环境条件,而民主政治的精髓就是通过有效的权力配置实现以权力制约权力。构建社会主义和谐社会,建立政治文明国家,就要从严治党,就要加强党内监督,尤其要加强对党的各级组织、党的领导干

政治机关建设方面存在的不足和改进(4篇)

政治机关建设方面存在的不足和改进

2024公安民警职务晋升(3篇)

公安民警职务晋升

小学思政课实施方案小学思政课实施方案(完整)

随着国家对素质教育要求的不断加强,小学思政课在课程中的地位也越来越重要,是实现全面育人的重要组成部分。小学思政课是指以道德素养、宪法法律、人生观价值观、民族精神、科学技术、文化艺术、体育健康等为核心,

2024落实第一议题制度会议记录(5篇)

落实第一议题制度会议记录

2024年度关于加强公安机关网络舆情风险防范工作部分思考

当前,随着互联网的广泛普及和信息技术的快速发展,各种社会思潮、意识形态、价值观念在网络上交织碰撞,所形成的“网络话语”逐渐成为重要的舆情力量,使当前的社会舆论环境发生重大而深刻的变化。以“两微一端”为

基督教为亡者祈祷经文6篇【完整版】

基督教为亡者祈祷经文(诗班唱诗歌,等候开会)主持人:基督徒()荣归天家追思礼拜现在开始。主持人:全体肃立、默哀(信徒祷告不超一分钟为好)……默哀毕。主持人:

那些借调人到底怎么留下来?(2024年)

上级单位之所以要“借调”,恰恰说明这个单位缺人,特别是缺能做事、会做事的人,这就意味着有打破“借而不调”僵局的希望,从而名正言顺一直留下来。下面我结合身边朋友的真实故事说说怎么“调”。方案一:保持耐心

共青团xx市委“喜迎二十大、永远跟党走、奋进新征程”主题教育实践活动启动仪式主持词(全文完整)

文章详情共青团xx市委喜迎二十大、永远跟党走、奋进新征程主题教育实践活动启动仪式主持词尊敬的领导、全体青年朋友们:在中国共产主义青年团成立100周年之际,共青团中央决定,围绕迎接和学习宣传贯彻党的二十

2023最新烈士陵园闹鬼鬼把孩子追到烈士陵园(五篇)

范文为教学中作为模范的文章,也常常用来指写作的模板。常常用于文秘写作的参考,也可以作为演讲材料编写前的参考。大家想知道怎么样才能写一篇比较优质的范文吗?接下来小编就给大家介绍一下优秀的范文该怎么写,我

意识形态方面方面存在问题和不足(4篇)

意识形态方面方面存在问题和不足

关于贯彻落实中央八项规定精神实施办法【完整版】

控制会议数量和规模。集团上下要严格执行集团相关会议管理办法,本着务实高效原则,切实减少各类会议活动,能不开的坚决不开,可以合并的坚决合并,严禁走形式、以会议代替落实。严格会议审批程序,集团、二级单位的