存储器管理

存储器的层次结构

enter description here
速度从高到低、容量从小到大

存储器管理的目的和功能

  • 主存储器的分配和管理
  • 提高主存储器的利用率
  • “扩充”主存容量
  • 存储保护

存储分配的三种方式

  • 直接指定方式(汇编地址写入)
  • 静态分配方式(程序装入时确定位置)
  • 动态分配方式

程序的装入和链接

将用户源程序变为可在内存中执行的程序:

  • 编译 翻译成机器级代码
  • 链接 使目标模块链接(引用的其它模块)成装入模块的过程
  • 装入 由装入程序将装入模块装入内存并执行

程序的装入

  • 绝对装入方式
  • 可重定位装入方式(静态、动态)
  • 动态运行时装入方式

程序的链接

  • 静态链接
  • 装入时动态链接
  • 运行时动态链接

连续分配存储管理方式

程序空间本来就是连续的用连续的内存装入连续的程序,减少管理工作的难度

  • 单一连续分配方式(一个进程在内存)

    • 优点:易于管理
    • 缺点:对要求内存空间少的程序,造成内存浪费;程序全部装入,很少使用的程序部分也占用内存。
  • 分区式分配方式(一个进程占据一个分区)

    • 固定分区分配
      • 易于实现,开销小
      • 内碎片造成浪费;分区总数固定,限制了并发执行的程序数目;存储空间的利用率太低
    • 动态分区分配——分区分配算法
  • 可重定位分区分配 定时把存储空间中的空白区合并为一个大的连续区 之前的可变式分区分配根据其要求量为其划定相应的区域。消除了 “内零头”,但造成“外零头”

分区分配算法

enter description here

  • 内零头(Internal Fragment):分配给用户但用户没有使用的空间 “多分配的空间”
  • 外零头(External Fragment ):没有分配但无法分配的空间,太小而无法分配,“分不出去的空间”

最佳适应算法BF

选择分区时总是寻找其大小最接近作业所要求的存储区域

  • 优点:遇到大作业到来时,比较容易得到满足
  • 缺点: 留下许多无法使用的空白区;回收时,把它插入空白区链也颇为费时

最坏适应算法WF

寻找最大的空白区

  • 缺点:将大空间分给了小作业后大作业来到无法满足申请

首次适应算法FF

空白区链的始端开始查找,选择第一个足以满足请求的空白块
分配后空白区被分成两部分一部分分配给作业;剩下的部分留在原空白区链中

  • 优点:简单,查找速度快
  • 缺点:存储空间利用率不高;找到合适空白区的速度降低。

循环首次适应算法NF

(下次适应算法)从上次查找结束的地方开始,找到一个足够大的空白区,就分配

  • 优点:存储空间的利用更加均衡
  • 缺点:需要获得相当大的空白区时,很难满足

快速适应算法QF

每一类具有相同容量的空闲分区,单独设立一个空闲分区链表
在内存中设立一张索引表,每一个表项记录空闲分区链表表头的指针
分配过程:根据进程的长度,寻找到能容纳它的最小空闲分区链表,并取下第一块进行分配即可

  • 优点:查找效率高;满足对大空间的需求,也不会产生内存碎片
  • 缺点:分区归还算法复杂,系统开销较大;以进程为单位,存在一定的浪费

伙伴系统

固定分区分配:并发执行的进程数量受到限制;内部碎片影响内存利用率
动态分区分配:算法复杂,回收分区时系统开销大

在伙伴系统中,可用内存块的大小为 2^k (1≤k≤m)

  • 2^1表示分配的最小块的尺寸;
  • 2^m表示分配的最大块的尺寸,通常是可供分配的整个内存空间的大小。

对空闲区按照大小分类,相同大小的分区链接为一个双向空闲链表;最多可形成 k(0 ≤k≤m )个链表。

分页存储管理方式

引入分页

  • 离散分配方式的引入:
    连续分配方式会产生内/外零头
    为解决零头问题又要进行紧凑等高开销活动
  • 什么是离散分配:程序在内存中不一定连续存放
  • 根据离散时的基本单位不同,可分为三种:
    分页存储管理
    分段存储管理
    段页式存储管理

分页存储管理基本思想

  • 离散的基础
    分页(Pages):将程序地址空间分页
    分块(Frames):将内存空间分块
    
  • 离散分配的体现
    • 内存一块可以装入程序一页
    • 连续的多个页不一定装入连续的多个块中
    • 注:系统中页块的大小是不变的。

离散分配没有外零头,且内零头肯定少于一个页面

分页存储管理的基本方法

如何建立程序空间与主存空间的映射——页表
如何进行地址变换——从程序逻辑地址到内存物理地址

页面和物理块

  • 页面或页(Page):把每个进程的逻辑地址空间分成一些大小相等的片。
  • 物理块或页框(Page Frame):内存空间也分成与页相同大小的若干存储块。在为进程分配存储空间时,总是以页框为单位。

页面大小由机器的地址结构决定通常在1KB~8KB之间。

实现分页存储管理的数据结构

  • 页表:进程,描述该进程的各页面在内存中对应的物理块号。页表中包括页号、物理块号。
  • 作业表:系统,记录作业的页表情况。
  • 空闲块表:系统,记录主存当前空闲块。

地址变换机构

使用寄存器:速度快,成本高
一般将页表存在内存进程的PCB中,运行时再装入页表寄存器PTR

分页系统中的地址变换过程如下:

  1. 根据逻辑地址,计算出页号和页内偏移量
  2. 从PTR中得到页表首址,然后检索页表,查找指定页面对应的页框号
  3. 用页框号乘以页面大小获得其对应的起始地址,并将其送入物理地址的高端
  4. 页内偏移量送入物理地址低端,形成完整的物理地址

快表

快表TLB为了提高地址变换速度,为进程页表设置一个专用的高速缓冲存储器其中专门保存当前进程最近访问过的一组页表项。
根据逻辑地址中的页号,会先查找快表中是否存在对应的页表项。
若快表中存在该表项,称为命中,取出其中的页框号加上页内偏移量计算出物理地址。
若快表中不存在该页表项,称为命中失败,则再查找页表,找到逻辑地址中指定页号对应的页框号。
同时,更新快表,将该表项插入快表中。

访问内存的有效时间 EAT

命中率a、查找快表时间b、访问内存时间c
有效访问时间EAT=a ✖ (b+c)+ (1- a) ✖ (b+2c)

两级和多级页表

引入两级页表采用离散分配方式,来解决难以找到一块连续的大内存空间的问题

利用离散分配方法实现的两级页表只是解决了大页表无需大片连续存储空间问题,但并未减少用较少内存去存放大页表问题,有关此类问题的成功解决方案在虚拟存储器管理中。

反置页表IPT

为了解决大页表问题占内存多现象,减少内存开销,避免一个进程一个页表。

IPT采用为主存中的每一个物理块建立一个页表项并按照块号排序,该表每个表项包含正在访问该物理块的进程标识、页号及特征位,用来完成主存物理块到访问进程的页号的转换。

即反过来查,原来是进程查物理现在是物理地址记录进程

对换

对换就是把内存中暂时不用的程序和数据换到外存,或把需要的程序和数据换入内存。
分为:

  • 整体对换 以进程为单位
  • 页面/分段对换:以页或段为单位

分段存储管理方式

根据程序模块化设计时会将程序分段(如主程序段、子程序段、数据段等)而分段管理便是按程序模块化设计思想分段存储。

  • 作业地址空间按逻辑信息的完整性被划分为若干个段;
  • 段内的地址空间是连续的;
  • 许多编译程序支持分段方式,自动根据源程序的情况产生若干个段。

分段较分页易于实现段的共享和段的保护。

段页式存储管理

  • 分页管理内存管理效率高
    • 没有外零头
    • 内零头小
  • 分段管理符合模块化思想
    • 每个分段都具备完整的功能
    • 方便代码共享、保护
    • 没有内零头,存在外零头

段页式管理结合:先将用户程序分段,每段内再划分成若干页,每段有段号,每段内部的页有一连续的页号。

但在段页式存储管理方式中,每访问一次数据,需访问三次内存。 访问段表、访问页表、访问相应数据,大大降低了访问速度。
可以设置快表,表项应包括段号、页号、物理块号。

总结:

  • 综合了分段和分页技术的优点,既能有效地利用存储空间,又能方便用户进行程序设计
  • 但是,实现段页式存储管理系统需要增加硬件成本,系统的复杂度和管理开销也大大增加
  • 因此,段页式存储管理技术适合于大、中型计算机系统,不太适合小型、微型计算机系统

虚拟存储器

虚拟存储器概述

传统内存管理的一次性和驻留性严重降低内存利用率,减少系统吞吐量
当一个程序要求的存储容量超过内存,或大量作业需要内存空间时
从物理上增加内存容量,增加系统成本,并且增加是有限的。
所以从逻辑上增加内存容量,是虚拟存储技术所要解决的主要问题。

当进程运行时,先将当前要运行的部分程序装入内存,其他部分暂留外存;
当要执行的指令不在内存时,处理器发生中断,通知操作系统将所缺部分从外存调入内存,保证程序继续执行;
当内存不足时,允许程序部分换入、换出。
enter description here

局部性原理

程序的执行总是呈现局部性。即在一个较短的时间段内,程序的执行仅限于某个部分。因此只要保证进程执行所需的部分程序和数据驻留在内存,一段时间内进程都能顺利执行。

具体表现为

  • 时间局限性 被访问过的数据可能再次被访问
  • 空间局限性 被访问过的存储单元其附近也可能被访问

虚拟存储器的定义

虚拟存储器:是指具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充的一种存储器系统。
是一种性能非常优越的存储器管理技术,故被广泛地应用于大、中、小型机器和微型机中。

虚拟存储器的特征

  • 多次性 多次性是指一个作业被分成多次调入内存运行。相对传统储存管理的一次性
  • 对换性 对换性是指作业的运行过程中进行换进、换出。换进和换出能有效地提高内存利用率。相对传统储存管理的常驻性
  • 虚拟性 虚拟性是指能够从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。

请求分页存储管理方式

工作原理:作业运行时,只将当前的一部分装入内存其余的放在辅存,一旦发现访问的页不在主存中,则发出缺页中断,由OS将其从辅存调入主存,如果内存无空块,则根据某种算法选择一个页淘汰以便装入新的页面。

利用这种方法,可使更多的作业处于就绪状态,且能支持比主存容量大的作业在系统中运行。从而提高存储空间利用率。

为了实现请求调页、页面置换两大功能,请求分页系统必须提供如下的硬件支持

  1. 请求分页的页表机制。
  2. 缺页中断机构。
  3. 地址变换机构。

内存分配策略

  • 固定分配局部置换 但是难以确定进程合适的分配大小
  • 可变分配全局置换(常用方式)预先分配用完再加
  • 可变分配局部置换 发现缺页后要换出再自行换入,不干涉其它区域

物理块分配算法

  • 平均分配算法
  • 按比例分配算法 根据进程的大小
  • 考虑优先权的分配算法

页面置换算法

最佳(优)置换算法OPT

理论上最理想的页面置换策略是:从主存中移出永远不再需要的页面;如无这样的页面存在,则应选择最长时间不需要访问的页面。

先进先出(FIFO)页面置换算法

实质是:总是选择作业中驻留时间最长(即最老)的一页淘汰。即:先进入主存的页面先退出主存。

最近最久未使用(LRU)置换算法

实质是:当需要置换一页面时,选择在最近一段时间内最久不用的页面予以淘汰。
特别的LRU需要硬件支持记录每个页面的最近使用情况

另有最少使用置换算法LFU:选择到当前时间为止被访问次数最少的页面被置换

简单Clock置换算法

此算法为每页设置一位访问位,再将内存中的所有页面都通过链接指针链接成一个循环队列。
具体操作:

  • 当某页被访问时,其访问位被置1。
  • 置换程序从上次停止位置开始检查页面的访问位。
    • 如果是0,就选择该页换出;
    • 若为1,则重新将它置0,给该页驻留内存的机会暂不换出。

例:
enter description here
enter description here

改进Clock置换算法

如果该页面驻留内存期间没有被修改过,那么不必把它写回辅存,否则系统必须把它写回辅存。
即相对简单CLOCK添加修改位

由访问位A和修改位M组合四种类型页面:

  1. 类(A=0,M=0):既未彼访问,又未被修改,是最佳淘汰页。
  2. 类(A=0,M=1):最近未被访问,但已被修改,并不是很好的淘汰页。
  3. 类(A=1,M=0):最近已被访问,但未被修改:该页有可能再被访问。
  4. 类(A=1,M=1):最近已被访问且被修改,该页可能再被访问。

缺页率对有效访问时间的影响

设内存读写周期为t,查找快表时间为λ,缺页中断处理时间为ɛ

  • 页面在内存且页表项在快表中,只需一次访问内存
    EAT= λ + t
  • 页面在内存但页表项不在快表中,需两次访问内存,一次读取页表,一次读取数据,另外还需更新快表。
    EAT= λ + t + t + λ=2(λ + t)
  • 页面不在内存:考虑查找快表时间、查找页表时间、缺页中断处理时间、更新快表时间、访问实际物理地址时间
    EAT= λ + t +ɛ + λ + t = ɛ + 2(λ + t)
    综上:
  • 引入快表命中率为α缺页中断率为f,则有效访问内存时间为
    EAT= λ + α t + (1- α)[t + f(t +ɛ +λ) + (1-f)(t +λ)]

抖动和工作集

抖动:如果运行进程的大部分时间都用于页面的换入/换出,而几乎不能完成任何有效的工作,则称此进程处于抖动状态。
抖动产生的原因有:

  • 进程分配的物理块太少
  • 置换算法选择不当
  • 全局置换使抖动传播

可利用抖动发生前出现的征兆发现抖动并加以防范。
这些技术有:

  • 采取局部置换策略
  • 引入工作集的算法
  • L=S准则 - L缺页之间的平均时间,S平均缺页服务时间
  • 选择暂停的进程

请求分段存储管理方式

工作原理:
请求分段系统中,程序运行之前,只需先调入若部分分段,便可启动运行。
当所访问的段不在内存中时,可请求OS将所缺的段调入内存。
硬件支持:

  • 请求分段的段表机制。
  • 缺段中断机构。
  • 地址变换机构。

段表机制

enter description here

环保护

环保护的基本原则是:
一个程序可以访问驻留在相同环或较低特权环中的数据
一个程序可以调用驻留在相同环或较高特权环中的服务。

习题4

P162

  1. 可采用哪几种方式将程序装入内存?它们分别适合何种场合
  • 绝对装入方式,适于单道程序环境
  • 可重定位装入方式,适于多道程序环境,静态存储分配
  • 动态运行时装入方式,适于多道程序环境,动态存储分配
  1. 何谓静态链接?静态链接需要解决两个什么问题
  • 静态链接:在程序运行之前,先将各目标模块及它们所需的库函数,链接成一个完整的装入模块(又称执行模块),以后不再拆开
  • 需要解决:将相对地址进行修改;变换外部调用符号
  1. 何谓运行时动态链接?运行时动态链接有何优点
  • 运行时动态链接:将某些目标模块的链接推迟到执行时才进行。
  • 优点:节省内存空间
  1. 在动态分区分配方式中,应如何将各空闲分区链接成空闲分区链
  • 按照地址递增的顺序链接分区:首次适应、循环首次适应
  • 按照分区大小顺序链接分区:最佳适应、最坏适应算法
  • 按分区的大小和分类链接成多条分区链:快速适应、伙伴系统、哈希算法
  1. 什么是基于顺序搜索的动态分区分配算法?分为哪几种
    它将空闲分区链接成空闲分区链,以此在分配时搜索链上分区,找到满足算法要求的分区
    分为首次适应算法、循环首次适应算法、最佳适应算法、最坏适应算法

  2. 在采用首次适应算法回收内存时,可能出现哪几种情况?应怎么处理

  • 回收区与上面的空闲分区邻接,合并,首地址仍是前一空闲分区的,不必为回收分区分配新表项,只需修改前一分区大小
  • 回收区与下面的空白区邻接,合并,重新使用新空闲区首址,修改大小
  • 回收区与上、下面的空白区邻接,合并,直接将后面空白区取消,修改大小,首地址仍是前一空闲分区的
  • 回收区与上、下面的空白区均不邻接,建立新表项
  1. 为什么要引入对换?对换可分为哪几种类型
    为了提高系统的吞吐量,提高内存的利用率和处理机的利用率;
    全局对换、局部对换。

  2. 为实现对换,系统应具备哪几方面的功能
    对对换空间的管理
    进程的换入、换出

  3. 基于离散分配时所用的基本单位不同,可将离散分配分为哪几种?
    分页存储管理方式、分段存储管理方式、段页式存储管理方式

  4. 什么是页表?页表的作用是什么?
    每个进程对应 1 个页表,描述该进程的所需各页面在内存中对应的物理块号。

  5. 为实现分页存储管理。需要哪些硬件支持?
    页表寄存器、物理地址寄存器和快表寄存器。
    地址变换机构。

  6. 在分页系统中是如何实现地址变换的?
    (1)根据逻辑地址,计算出页号和页内偏移量;
    (2)从PTR中得到页表首址,然后检索页表,查找指定页面对应的页框号;
    (3)用页框号乘以页面大小获得其对应的起始地址,并将其送入物理地址的高端。
    (4)将页内偏移量送入物理地址低端,形成完整的物理地址。

  7. 在具有快表的段页式存储管理方式中,如何实现地址变换?
    根据逻辑地址中的页号,查找快表中是否存在对应的页表项。
    若快表中存在该表项,称为命中(hit),取出其中的页框号,加上页内偏移量,计算出物理地址。
    若快表中不存在该页表项,称为命中失败,则再查找页表,找到逻辑地址中指定页号对应的页框号。同时,更新快表,将该表项插入快表中。并计算物理地址

  8. 分页和分段存储管理有何区别?
    页是信息的物理单位,而段是信息的逻辑单位。
    页的大小固定而且由系统决定,段的大小不固定,通常由编译程序划分。
    分页用户程序地址空间是一维的,分段用户程序地址空间是二维的。

  9. 试全面比较连续分配和离散分配方式。
    连续分配程序空间本来就是连续的,用连续的内存装入连续的程序,减少管理工作的难度
    离散分配方式需要额外的硬件支持,且实现的算法相对比较复杂
    没有外零头 不受连续空间限制,每块都能分出去,仅有小于一个页面的内零头 程序大小一般不是页大小的整数倍。

P189

  1. 什么是程序运行时的时间局限性和空间局限性?

    • 时间局限性 被访问过的数据可能再次被访问
    • 空间局限性 被访问过的存储单元其附近也可能被访问
  2. 实现虚拟存储器需要哪些硬件支持?
    请求分页/段的页/段表机制
    缺页/段中断机构
    地址变换机构

  3. 实现虚拟存储器需要哪些关键技术?
    请求调页/段功能、页面置换功能

  4. 请详细说明请求分页系统的地址变换过程。

    1. 取逻辑地址分解为页号和页内偏移
    2. 根据页号查找页表,获得该页的描述信总
    3. 若该页中断位为1,产生缺页中断
    4. 更新该页的描述信息
    5. 根据页块号和页内偏移,计算物理地址。
  5. 试说明在请求分页系统中页面的调入过程。
    当程序要访问的页面未在内存时,便向CPU发出缺页中断,中断处理程序通过查找页表,得到该页在外存的物理块后,如果此时内存能容纳新页,则启动磁盘将所缺之页调入内存,然后修改页表。
    如果内存已满,则须先按照置换算法从内存中选出一页准备换出,然后再把所缺的页调入内存,并修改页表中的相应表项,并将此页表项写入快表中。
    在缺页调入内存后,修改后的页表形成所要访问数据的物理地址,再去访问内存数据。
    整个页面的调入过程对用户是透明的。

  6. 在请求分页系统中,常采用哪几种页面置换算法?
    最佳置换算法OPT
    先进先出置换算法FIFO
    最近最久未使用置换算法LRU
    最少使用置换算法LFU
    简单的Clock置换算法
    改进型Clock置换算法

  1. 在请求分页系统中,产生“抖动”的原因是什么?
    • 进程分配的物理块太少
    • 置换算法选择不当
    • 全局置换使抖动传播

概念

链码事件

Hyperledger Fabric采用异步通信的模式来进行开发,可以在链码里面定义某些事件,然后通过应用程序去监听,当某个事件被触发的时候,就可以执行预先设定好的回调函数了
具体体现在cc的invoke

账本与通道

账本是通过通道(channel)进行隔离的,这种隔离不仅体现在逻辑上,在物理上也是进行分隔的。

智能合约与交易的关系

智能合约相当于函数的声明与定义,而交易相当于函数的一次调用

身份

Hyperledger Fabric利用的PKI体系(公钥架构,在网络中提供安全通信的技术,让HTTP变成HTTPS)和CA系统,提供了包括注册登录,身份认证等待功能。这里的注册登录是指能与区块链底层进行交互的一个身份的管理,一个应用程序可能只需要一个身份就可以完成所有与区块链底层交互的功能。
注册登记,客户端向CA机构表名自己的身份,然后从CA机构获取相应的证书,用于后续的操作,比如交易提案,交易提交等等(CA在区块链外,可以是一个第三方CA)

CAP

区块链这样的典型的分布式系统中,他保证每一个节点都有一份完整的数据,都可以对外提供完整的服务。因此区块链是弱化了一致性C,正因为区块链弱化了一致性,所以需要更好的共识算法保证一致性。

PEER

Peer节点是一个统称,包含了Leader(主节点),Anchor(锚节点),Endorser(背书节点)以及Committer(记账节点)

Leader主节点连接到Orderer节点并与之通信并通知给组织内部的其他节点
Anchor锚节点是在通道上可以被所有其他Peer节点发现的节点

Orderer

从全网的客户端节点接收交易,然后将交易按照一定的规则进行排序
将排序好的交易按照固定的时间间隔打包成区块,然后分发给其他组织的主节点

有两种常用类型的排序方法:

  • solo,整个网络中只有一个排序节点,它收到的交易的顺序就是整个网络中的排好序的交易顺序。整个模式仅仅适用于开发和测试时用,如果Orderer节点挂掉了,整个网络就是瘫痪的
  • kafka,将整个网络中的交易排序过程转交给了kafka集群,每一个Orderer节点都是kafka集群的生产者和消费者,生产者将从客户端节点接收到的交易转发给kafka集群,同时消费者中kafka集群里面获取交易,这样或得到的交易就已经是排好序的了

————————————————
转自CSDN博主「TLpigff」的文章,遵循CC 4.0 BY-SA版权协议
原文链接:https://blog.csdn.net/lvyibin890/category_10008527.html

1-8周

Checksum校验和

请分别按 16 bit一组和 8 bit 一组计算计算以下数据 Checksum,分块儿后不足的请在尾部用0补足。
0xC0A800010ACBD1223
答案:3368

算法

第一步:补零
第二部:4位累加,溢出做0001加
第三步:二进制取反

7-16周

请计算以下数据的校验和(16 bit一组):

1
2
3
4
5
6
{
0XC0A8,
0X0001,
0xACBD,
0X1223
}

答案:8075

TCP定时器所采用的指数加权移动平均算法中,指数的提法从何而来?

TCP TimeoutInterval 算法:
EstimatedRTT = (1−α)⋅EstimatedRTT + α⋅SampleRTT
DevRTT=(1−β)⋅DevRTT+β⋅|SampleRTT−EstimatedRTT|
TimeoutInterval=EstimatedRTT+4⋅DevRTT
α=1/8 β=1/4

参见下图,假设网络初始构建,若PC0 ping PC1,请简述它们之间的完整通信过程。

win64 or linux64内存对齐

#include<stdio.h>
int main(){
struct {char a;int b;char c;}X2;//1+3+4+1+3=12
struct {int a;char b;}X3;//4+1+3=8
struct {char a;short b;}X4;//1+1+2=4
struct {char a;short b;char c;}X5;//1+1+2+1+1=6
struct {char a;long b;}X6;//1+3+4=8 or 1+7+8=16
struct {char a;long b;char c;}X7;//1+3+4+1+3=12 or 1+7+8+1+7=24
struct {char a;long long b;}X8;//1+7+8=16
struct {char a;long long b;char c;}X9;//1+7+8+1+7=24
struct {char a;int b;short c;}X10;//1+3+4+2+2=12
struct {char a;short b;char c;int d;}X11;//1+1+2+1+3+4=12
printf(“%ld\n”,sizeof(X2));
printf(“%ld\n”,sizeof(X3));
printf(“%ld\n”,sizeof(X4));
printf(“%ld\n”,sizeof(X5));
printf(“%ld\n”,sizeof(X6));
printf(“%ld\n”,sizeof(X7));
printf(“%ld\n”,sizeof(X8));
printf(“%ld\n”,sizeof(X9));
printf(“%ld\n”,sizeof(X10));
printf(“%ld\n”,sizeof(X11));

}




ERC721

《什么是ERC-721 代币?》
《智能合约NFT之ERC721代币详解》

本质上说就是定义的函数接口标准

ERC721标准

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
pragma solidity ^0.4.20;


interface ERC721 {
/// @dev 当任何NFT的所有权更改时(不管哪种方式),就会触发此事件。
/// 包括在创建时(`from` == 0)和销毁时(`to` == 0), 合约创建时除外。
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

/// @dev 当更改或确认NFT的授权地址时触发。
/// 零地址表示没有授权的地址。
/// 发生 `Transfer` 事件时,同样表示该NFT的授权地址(如果有)被重置为“无”(零地址)。
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

/// @dev 所有者启用或禁用操作员时触发。(操作员可管理所有者所持有的NFTs)
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

/// @notice 统计所持有的NFTs数量
/// @dev NFT 不能分配给零地址,查询零地址同样会异常
/// @param _owner : 待查地址
/// @return 返回数量,也许是0
function balanceOf(address _owner) external view returns (uint256);

/// @notice 返回所有者
/// @dev NFT 不能分配给零地址,查询零地址抛出异常
/// @param _tokenId NFT 的id
/// @return 返回所有者地址
function ownerOf(uint256 _tokenId) external view returns (address);

/// @notice 将NFT的所有权从一个地址转移到另一个地址
/// @dev 如果`msg.sender` 不是当前的所有者(或授权者)抛出异常
/// 如果 `_from` 不是所有者、`_to` 是零地址、`_tokenId` 不是有效id 均抛出异常。
/// 当转移完成时,函数检查 `_to` 是否是合约,如果是,调用 `_to`的 `onERC721Received` 并且检查返回值是否是 `0x150b7a02` (即:`bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`) 如果不是抛出异常。
/// @param _from :当前的所有者
/// @param _to :新的所有者
/// @param _tokenId :要转移的token id.
/// @param data : 附加额外的参数(没有指定格式),传递给接收者。
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;

/// @notice 将NFT的所有权从一个地址转移到另一个地址,功能同上,不带data参数。
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

/// @notice 转移所有权 -- 调用者负责确认`_to`是否有能力接收NFTs,否则可能永久丢失。
/// @dev 如果`msg.sender` 不是当前的所有者(或授权者、操作员)抛出异常
/// 如果 `_from` 不是所有者、`_to` 是零地址、`_tokenId` 不是有效id 均抛出异常。
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

/// @notice 更改或确认NFT的授权地址
/// @dev 零地址表示没有授权的地址。
/// 如果`msg.sender` 不是当前的所有者或操作员
/// @param _approved 新授权的控制者
/// @param _tokenId : token id
function approve(address _approved, uint256 _tokenId) external payable;

/// @notice 启用或禁用第三方(操作员)管理 `msg.sender` 所有资产
/// @dev 触发 ApprovalForAll 事件,合约必须允许每个所有者可以有多个操作员。
/// @param _operator 要添加到授权操作员列表中的地址
/// @param _approved True 表示授权, false 表示撤销
function setApprovalForAll(address _operator, bool _approved) external;

/// @notice 获取单个NFT的授权地址
/// @dev 如果 `_tokenId` 无效,抛出异常。
/// @param _tokenId : token id
/// @return 返回授权地址, 零地址表示没有。
function getApproved(uint256 _tokenId) external view returns (address);

/// @notice 查询一个地址是否是另一个地址的授权操作员
/// @param _owner 所有者
/// @param _operator 代表所有者的授权操作员
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

解析与实现

Transfer event

当任何NFT的所有权更改时(不管哪种方式),就会触发此事件,即成立为交易(包括创建,转让,销毁)

Approval event

当更改或确认NFT的授权地址时触发。

ApprovalForAll event

所有者启用或禁用授权第三方(操作员)管理时触发。

balanceOf*

查找owner的资产数量,参数_owner,返回数量

ownerOf*

查找资产对应所有者,参数资产tokenid,返回拥有者

safeTransferFrom

安全的资产所有权转移(修改owner),参数当前所有者、目的所有者、资产tokenid、任意备注(可不带)

transferFrom*

资产所有权转移,相比safeTransferFrom参数一致

approve*

更改或确认NFT的授权地址,参数新授权人、资产tokenid

setApprovalForAll

所有者启用或禁用授权第三方(操作员)管理,参数要授权的的操作员、启用/禁用布尔值

getApproved*

获取资产授权地址,参数资产tokenid,返回授权地址

isApprovedForAll

查询一个操作员是否是一个所有者的授权操作员,参数所有者、操作员

链码分析

资产本身的信息是一组需要区块链记录的结构体,还有每次进行交易时希望对交易信息进行记录则交易信息也设定为一结构体(特殊类型定义为string 设置为宏定义方便转换用)

参考
从0到1:Hyperledger Fabric开发精要【最系统】
hubwiz私人博客
CSDN TLpigff博客
CSDN 烟火不完美博客

github.com/hyperledger/fabric/core/chaincode/shim
github.com/hyperledger/fabric/protos/peer
改为
github.com/hyperledger/fabric-chaincode-go/shim
github.com/hyperledger/fabric-protos-go/peer

报错:undefined:discovery.ChaincodeCall
go.mod中
github.com/hyperledger/fabric-protos-go v0.0.0-20211006172752-14f4318ce71c
改为
github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23

开发流程

以目录为检索结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
│  config.yaml
│ main.go//重点,执行入口

├─chaincode
│ │ edu.go//业务层重点
│ │ go.mod
│ │ go.sum
│ └─vendor

├─fixtures
│ │ configtx.yaml//网络层重点
│ │ crypto-config.yaml//网络层重点
│ │ docker-compose.yaml//网络层重点
│ ├─channel-artifacts
│ └─crypto-config

├─sdkInit
│ integration.go//重点
│ sdkInfo.go//重点
│ sdkSetting.go//重点

├─service
│ domain.go//业务层重点
│ eduService.go//业务层重点

└─web//常见go网页应用工程MVC模式
│ webServer.go//各种http.HandleFunc
├─controller
├─static
└─tpl

fixtures

三种配置文件、根据配置文件生成的组织结构以及基础区块

crypto-config.yaml

用于生成相关组织的私钥和证书
Fabric 中会有两种类型的公私钥和证书

  • 给节点之间通讯安全而准备的TLS证书
  • 用户登录和权限控制的用户证书。

配置参考crypto-config配置参考

configtx.yaml

configtx.yaml主要用来配置fabric的组织结构,通道及锚节点的配置。它主要完成以下几个功能:

  • 生成启动 Orderer 需要的创世区块orderer.block(genesis.block)
  • 创建应用通道所需的配置交易文件
  • 生成组织锚节点更新配置交易文件

配置参考configtx配置参考
之后可以使用configtxgen进行生成操作

docker-compose.yaml

用以配置fabric网络的相关容器
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。
fabric区块链中多使用docker来创建虚拟容器

chaincode

链码,合约,或者这里我们理解为接口API
是在可执行代码中定义不同组织之间业务规则的代码
是业务逻辑中需要的组织交互逻辑而不是全部业务逻辑

sdkinit

这一块结合main.go主函数理解,主要用于初始化启动SDK

按执行顺序

.sh脚本内容:

1
2
3
4
5
6
7
8
9
10
11
12
sudo docker rm -f $(sudo docker ps -aq)
sudo docker network prune
sudo docker volume prune
删除可能的网络与容器
cd fixtures && docker-compose up -d
启动docker容器(按fixtures配置)
cd ..
sudo rm education
go build
编译主函数
./education
执行

第一步:

sdkInit.Setup
包含

  • fabsdk.New
  • sdk.Context

主要工作:初始化SDK

第二步:

sdkInit.CreateAndJoinChannel
包含

  • createChannel
  • org.OrgResMgmt.JoinChannel

主要工作:创建通道并将组织加入通道

第三步:

sdkInit.CreateCCLifecycle
分为:

  • 打包智能合约
  • 安装智能合约
  • “认可”智能合约(Approve)
  • 智能合约初始化

主要工作:智能合约上链与初始化

第四步:

service.InitService
包含

  • sdk.ChannelContext
  • channel.New

主要功能:创建通道客户端实例。
通道客户端用于查询链码,执行链码,注册/取消特定通道上的链码事件。

第五步

serviceSetup.SaveEdu
进行交易实验(添加信息)
可跳过

第六步

serviceSetup.FindEduInfoByEntityID
进行交易实验(查询信息)
可跳过

第七步

1
2
3
4
fmt.Println("第七步")
app := controller.Application{
Setup: serviceSetup,
}

启动服务

第八步

1
2
fmt.Println("第八步")
web.WebStart(app)

建立服务网站

怎么调用链码的

req := channel.Request{ChaincodeID: t.ChaincodeID, Fcn: "addEdu", Args: [][]byte{b, []byte(eventID)}}
用这种语句在GO中调用链码写入信息

couchDB

fabric支持的唯二数据库,是一个NoSQL文档存储数据库。
它使用JSON存储数据(文档),使用http协议为api访问文档,使用Web浏览器查询索引。

问题:为什么老是运行的以前的链码?

太大意了!

已经将文件命名为5edu了,却没有改对应路径QAQ

交换、路由和无线基础

基本设备配置

使用初始设置配置交换机

在一台思科交换机开机之后,会经过五步启动顺序:

  • 步骤 1: 首先,交换机会加载一个存储在ROM中的上电自检 (POST) 程序。POST 会校验CPU子系统。它会测试 CPU、DRAM 以及构成 Flash 文件系统的闪存设备部分。
  • 步骤 2: 接下来,交换机加载启动加载程序软件。启动加载程序是存储在 ROM 中并在 POST 成功完成后立即运行的小程序。
  • 步骤 3: 启动加载程序执行低级 CPU 初始化。启动加载程序初始化 CPU 寄存器,寄存器控制物理内存的映射位置、内存量以及内存速度。
  • 步骤 4: 启动加载程序初始化系统主板上的 Flash 文件系统
  • 步骤 5: 最后,启动加载程序找到并将默认的 IOS 操作系统软件映像加载到内存,并将对交换机的控制权转交给 IOS。

boot system 命令

使用 boot system 全局配置模式命令来设置 BOOT 环境变量。
如:boot system flash:/c2960-lanbasek9-mz.150-2.SE/c2960-lanbasek9-mz.150-2.SE.bin
| 命令 | 定义 |
| — | — |
| boot system| 主命令。 |
| flash:| 存储设备 |
| c2960-lanbasek9-mz.150-2.SE/| 文件系统的路径 |
| c2960-lanbasek9-mz.150-2.SE.bin| IOS 文件名称 |

交换机 LED 指示灯

  • SYST - 系统LED
  • RPS - 冗余电源系统LED
  • STAT - 端口状态LED
  • DUPLX - 端口双工模式LED
  • SPEED - 端口速率LED
  • POE - 以太网端口供电LED

从系统崩溃中恢复

配置交换机端口

安全远程访问

路由器基本配置

验证直连网络

交换的概念

帧转发

交换域

数据库及其系统概念

数据

数据(Data)是数据库中存储的基本对象

  • 数据的定义
    描述事物的符号记录
  • 数据的种类
    文字、图形、图象、声音
  • 数据的特点
    数据与其语义是不可分的

数据库

数据库的定义
数据库(Database,简称DB)是长期储存在计算机内、有组织的、可共享的大量数据的集合。
数据库的基本特征

  • 数据按一定的数据模型组织、描述和储存
  • 可为各种用户共享
  • 冗余度较小
  • 数据独立性较高
  • 易扩展

概括地讲,数据库具有永久存储有组织可共享三个基本特点。

数据库管理系统

  • 什么是DBMS:
    数据库管理系统(Database Management System,简称DBMS)是位于用户与操作系统之间的一层数据管理软件。
  • DBMS的用途:
    科学地组织和存储数据、高效地获取和维护数据

功能

  • 数据定义功能
    提供数据定义语言(DDL) 定义数据库中的数据对象
  • 数据组织、存储和管理
    分类组织、存储和管理各种数据
    确定组织数据的文件结构和存取方式
    实现数据之间的联系
    提供多种存取方法提高存取效率
  • 数据操纵功能
    提供数据操纵语言(DML)
    实现对数据库的基本操作 (查询、插入、删除和修改)
  • 数据库的事务管理和运行管理
    数据库在建立、运行和维护时由DBMS统一管理和控制 保证数据的安全性、完整性、多用户对数据的并发使用 发生故障后的系统恢复
  • 数据库的建立和维护功能(实用程序)
    数据库初始数据装载转换
    数据库转储
    介质故障恢复
    数据库的重组织
    性能监视分析等
  • 其它功能
    DBMS与网络中其它软件系统的通信
    两个DBMS系统的数据转换
    异构数据库之间的互访和互操作

数据模型

数据模型是指描述事物对象的数据结构组成、数据语义联系、数据约束的抽象结构及其说明

  1. 数据结构: 用于描述事物对象的静态特征,包括事物对象的数据组成、数据类型、数据性质等。
  2. 数据操作:用于描述事物对象的动态特征,包括数据的插入、修改、删除和查询等访问操作。
  3. 数据约束:用于描述数据结构中数据之间的语义联系、数据之间的制约和依存关系,以及数据动态变化的规则等。
    有:

层次数据模型、网状数据模型、关系数据模型、其它数据模型(如对象数据模型、键值对数据模型、列式数据模型、文档数据模型、图形数据模型等)

数据库系统

数据库系统(Database Systems)是一类基于数据库进行数据管理与信息服务的软件系统。数据库系统由用户、数据库应用程序、数据库管理系统和数据库四个部分组成

关系数据库中数据内容

在关系数据库中,除了存储和管理应用的用户数据外,还需要存储与管理数据库本身的元数据索引数据运行数据等系统数据。

数据库系统应用结构

单机用户结构、单机用户结构、客户/服务器结构、分布式结构

数据库应用系统生命周期

需求分析、系统设计、系统实现、系统测试、系统运行与维护

典型数据库管理系统

ACCESS——微软公司推出的桌面数据库管理系统
SQL SERVER——微软公司推出的商用数据库管理系统
Oracle Database——甲骨文公司推出的企业级数据库管理系统
IBM DB2——IBM公司推出的企业级数据库管理系统
Sybase ASE——Sybase公司推出的企业级数据库管理系统
MySql——应用广泛的开源关系数据库管理系统
PostgreSQL——技术领先的开源对象-关系数据库管理系统
Sybase SQL Anywhere——Sybase推出的移动计算数据库管理系统
SQLite——开源的轻量级嵌入式数据库管理系统

关系及其相关概念

关系、实体

实体(entity)——是指包含有数据特征的事物对象在概念模型世界中的抽象名称。
关系(relation)——是指具有关系特征、用于存放实体数据的二维表。关系也常被称为关系表。

关系键

在关系中,可以用来唯一标识元组的属性列,称为键(Key),其它属性列都为非键列。

  • 复合键(Compound Key)——是指关系中用来唯一标识元组的多列作为键。
  • 候选键(Candidate Key)——关系中可能有多个列均适合作为键,将其中每个都称为候选键。
  • 主键(Primary key)是关系表中最有代表性的一个候选键,每个关系表中只能定义一个主键。
    主键作用:
    • 唯一标识关系表的每行(元组)
    • 与关联表的外键建立联系,实现关系表之间连接
    • 数据库文件使用主键值来组织关系表的数据存储
    • 数据库使用主键索引快速检索数据
  • 代理键——采用DBMS自动生成的数字序列作为关系表的主键。

关系模型

关系模型(Relation Model)——是一种基于二维表结构存储数据实体及实体间联系的数据模型。
数据结构数据操作方式数据关系约束组成。

关系模型的操作

选择、投影、连接、除

  • 选择 - 行选择
  • 投影 - 列选择
  • 连接 - θ连接(全匹配)自然连接(一一对应)外连接(相对于前,不丢失填空值)
  • 除 - 取第一个表能代表概括第二个表的值

完整性约束

关系模型完整性

关系模型完整性是指在关系数据模型中对关系实施的完整性约束。
完整性约束作用:

  • 消除关系表的元组重复存储
  • 保持关联表的数据一致性
  • 实现业务数据规则

关系模型完整性约束组成:

  • 实体完整性约束
  • 参照完整性约束
  • 用户自定义完整性约束

实体完整性

实体完整性是指在关系表中实施的主键取值约束,以保证关系表中的每个元组可以被唯一标识
实体完整性约束规则

  • 每个关系表中的主键属性列都不允许为空值(NULL),否则就不可能标识实体。
  • 现实世界中的实体是靠主键来标识,主键取值应该唯一,并区分关系表中的每个元组。

参照完整性

参照完整性是指关系表之间需要遵守的数据约束,以保证关系之间关联列的数据一致性
参照完整性约束规则:若关系R中的外键F与关系S中的主键K相关联,则R中外键F值必须与S中主键K值一致。

外键(Foreign key)——在关联的两个关系中,它们具有一个或多个相同属性。若关联列在第一个关系中作为主键,则在第二个关系中作为外键。

用户自定义完整性

用户自定义完整性是指用户根据具体业务对数据处理规则要求所定义的数据约束。
用户可以定义如下类型的完整性约束:

  • 定义列的数据类型与取值范围
  • 定义列的缺省值
  • 定义列是否允许取空值
  • 定义列取值唯一性
  • 定义列之间的数据依赖性

操作系统引论

目标和作用

目标:方便性、有效性、可扩展性、开放性
作用

  1. 作为用户与计算机硬件系统之间的接口
  2. 操作系统作为计算机系统资源的管理者
  3. 实现了对计算机资源的抽象

发展过程

人工操作方式、脱机输入输出方式
单批道处理系统
多批道处理系统(资源利用率高,系统吞吐量大,平均周转时间长,无交互能力)
分时系统(多路性、独立性、及时性、交互性)
实时系统(多路性、独立性、及时性、交互性、可靠性)
微机操作系统(单用户多用户)

基本特征

  • 并发 - 并发性是指两个或多个事件在同一时间间隔内发生,而并行性是指两个或多个事件在同一时刻发生。
  • 共享 - 资源共享是指系统中的资源可供内存中多个并发执行的进程共同使用。一段时间内只允许一个进程访问的资源称为临界资源一个进程访问结束并释放系统资源后才允许另一进程对该资源访问的方式称为互斥访问
  • 虚拟 - 通过空分复用时分复用技术将一条物理信道变为若干条逻辑信道的技术
  • 异步 - 进程的执行本身具有异步性(不可预知完成时间与顺序)所以要设计同步机制

主要功能

处理机管理功能

  • 进程控制
  • 进程同步
  • 进程通信
  • 调度

内存管理功能

  • 内存分配
  • 内存保护
  • 地址映射
  • 内存扩充

(I/O)设备管理功能

  • 缓冲管理
  • 设备分配
  • 设备处理

文件管理功能

  • 文件存储空间管理
  • 目录管理
  • 文件读写管理与保护

操作系统与用户之间的接口

  • 用户接口(联机用户接口、脱机用户接口、程序接口)
  • 程序接口

结构设计

无结构

程序紧凑,高效利用内存
但是随着系统的不断扩大,所设计出的操作系统就会变得既庞大又杂乱。
一方面会使编制的程序错误很多给调试工作带来困难
另一方面也使程序难以阅读和理解,增加了维护负担

模块化结构

模块化OS由程序设计的模块化设计思想演变而来
衡量模块化设计的两个标准:内聚性、耦合性
优点:

  1. 提高OS设计的正确性、可理解性和可维护性。
  2. 增强OS的可适应性。
  3. 加速OS开发过程。
    问题:
  4. 最初模块接口规定难以满足实际需求
  5. 无序设计

分层式结构

将模块接口法中对模块的设计顺序由无序变为有序,自底向上分层设计
优点:

  1. 易保证系统的正确性
  2. 易扩充和易维护性
    缺点:
  3. 系统效率降低:单向依赖的层次使得必须建立层次之间的通信机制增加通信开销

习题

  1. 设计现代OS的主要目标是什么?
    方便性、有效性、可扩展性、开放性

  2. 试说明推动分时系统形成和发展的主要动力是什么。
    满足人机交互需求,实现共享主机

  3. 为什么要引入实时操作系统?
    更好的满足实时控制实时信息处理领域对时间控制的需求

  4. 试从交互性、及时性以及可靠性方面将分时系统与实时系统进行比较。
    交互性:实时系统的交互性不像分时系统为终端用户提供数据和资源共享服务,而限于特定专用服务程序
    及时性:分时系统的响应时间间隔通常为人们所能接受的1~3秒,实时系统由截至时间所确定通常为秒级到毫秒级
    可靠性:实时系统相比分时系统要求更高的可靠性,所以采取多级容错措施保障系统的安全性

  5. OS有几大特征?最基本的特征是什么?
    并发性、共享性、虚拟性、异步性;并发性最基本

  6. 处理机管理有哪些主要功能?其主要任务是什么?
    进程控制、进程同步、进程通信、调度
    创建进程结束进程控制正在运行的进程、使多个进程有序同步进行、交换进程任务的信息、选择作业分配资源运行的作业调度和选择进程分配处理器设置现场执行的进程调度

  7. 存储器有哪些主要功能?其主要任务是什么?
    内存分配、内存保护、地址映射、内存扩充
    为程序分配内存空间、确保程序运行空间不干扰、将逻辑地址映射为物理地址、实现调用置换等功能

  8. 设备管理有哪些主要功能?其主要任务是什么?
    缓冲管理、设备分配、设备处理
    完成用户IO请求分配所需IO设备执行IO操作、提高CPU和IO设备的利用率提高IO速度方便用户使用

  9. 文件管理有哪些主要功能?其主要任务是什么?
    文件存储空间管理、目录管理、文件读写管理与保护
    分配外存空间提高外存利用率、为文件建立目录加以有效组织、根据用户请求读写外存数据、防止文件被非法窃取和受到破坏保障文件安全性

进程的描述与控制

前趋图和程序执行

前趋图(Precedence Graph)是一个有向无循环图,用于描述进程之间执行的前后关系。

程序的顺序执行

  • 顺序性
  • 封闭性
  • 可再现性

程序的并发执行

  • 间断性
  • 失去封闭性
  • 不可再现性

进程的描述

而由程序段、相关的数据段和PCB三部分便构成了进程实体。

典型定义

  1. 进程是程序的一次执行。
  2. 进程是一个程序及其数据在处理机上顺序执行时所发生的活动。
  3. 进程是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位

特征

  • 动态性
  • 并发性
  • 独立性
  • 异步性

状态

IMG_20220304_151207_edit_772433114767030

PCB数据结构

  1. 进程标识符 - 用于惟一地标识一个进程。分为内部标识符和外部标识符
  2. 处理机状态 - 组成:①通用寄存器②指令计数器③程序状态字PSW④用户栈指针
  3. 进程调度信息 - 包括:①进程状态②进程优先级③进程调度所需的其它信息④事件,阻塞原因
  4. 进程控制信息 - ①程序和数据的地址 ②进程同步和通信机制 ③资源清单 ④链接指针
pid
进程状态
现场
优先级
阻塞原因
程序地址
同步机制
资源清单
链接指针

PCB的组织方式

  1. 线性方式 将系统中的所有PCB组织在一张线性表中,将该表的首地址存放在一个专用区域中。
  2. 链接方式 把具有同一状态的PCB,用其中的链接字链接成一个队列,排成就绪队列,若干个阻塞队列以及空白队列。
  3. 索引方式 系统根据所有进程的状态建立几张索引表。

进程控制

进程控制是用于创建一个新进程,终止一个已完成的进程,或去终止一个因出现某事件而使其无法运行下去的进程,还负责进程运行中的状态转换。

操作系统内核

OS内核—-常驻内存。
包含与硬件紧密相关的模块(中断处理) 常用设备驱动、运行频率高的模块(时钟管理、进程调度)
目的:1、保护;2、提供OS效率

  1. 支撑功能 - 中断处理 时钟管理 原语操作
  2. 资源管理功能 - 进程管理 存储器管理 设备管理

进程的创建

进程的层次结构

即父进程、子进程(可以继承父进程所拥有的资源)

引起创建进程的事件

  1. 用户登录
  2. 作业调度
  3. 提供服务
  4. 应用请求

进程创建

调用进程创建原语Creat( )按下述步骤创建一个新进程:

  1. 申请空白PCB。
  2. 为新进程分配资源。
  3. 初始化进程控制块。包括:
    ①初始化标识信息。
    ②初始化处理机状态信息。
    ③初始化处理机控制信息。
  4. 将新进程插入就绪队列。

进程的终止

引起进程终止的事件

  1. 正常结束: 批处理中用Holt指令,分时中用Logs off指令。
  2. 异常结束:
    ①越界错误。存储区。
    ②保护错。写一个只读文件。
    ③非法指令。执行一条不存在的指令。
    ④特权指令错。用户访问只允许OS执行的指令。
    ⑤运行超时。
    ⑥等待超时。
    ⑦算术运算错。被0除。
    ⑧I/O故障。
  3. 外界干预:外界干预并非指在本进程运行中出现了异常事件,而是指进程应外界的请求而终止运行。
    ① 操作员或操作系统干预。
    ② 父进程请求终止该进程。
    ③ 当父进程终止时,OS也将他的所有子孙进程终止。

进程的终止过程

  1. 根据被终止进程的标识符ID,从PCB集合中检索出该进程的PCB,从中读出该进程的状态。
  2. 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新进行调度。
  3. 若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。
  4. 将被终止进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。
  5. 将被终止进程(它的PCB)从所在队列(或链表)中移出,等待其他程序来搜集信息。

进程的阻塞与唤醒、挂起与激活

引起进程阻塞的事件

  1. 请求系统服务:提出I/O服务时,并不立即满足该进程的要求时,转变为阻塞状态来等待
  2. 启动某种操作:当进程启动某种操作后,在该操作完成之后才能继续执行。
  3. 新数据尚未到达:对于相互合作的进程而言。
  4. 无新工作可做。如发送进程。

进程阻塞过程

正在执行的进程,当发现上述某事件时,由于无法继续执行,于是进程便通过调用阻塞原语block( )把自己阻塞。

  1. 把进程控制块中的现行状态由“执行”改为“阻塞”,并将PCB插入阻塞队列。
  2. 转调度程序进行重新调度,将处理机分配给另一就绪进程,并进行切换。

进程唤醒过程

当被阻塞进程所期待的事件出现时,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup( ),将等待该事件的进程唤醒。

  1. 首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪
  2. 然后再将该PCB插入到就绪队列中。

进程的挂起

当出现了引起进程挂起的事件时,系统将利用挂起原语suspend( )将指定进程进程挂起。

  1. 首先检查被挂起进程的状态,若处于活动就绪状态,便将其改为静止就绪;
  2. 对于活动阻塞状态的进程,则将之改为静止阻塞状态。

进程的激活

当发生激活进程的事件时,则可将在外存上处于静止就绪状态的进程换入内存。 系统利用激活原语active( )将指定进程激活:

  1. 激活原语先将进程从外存调入内存,检查该进程的现行状态;
  2. 若是静止就绪,便将之改为活动就绪;若为静止阻塞,便将之改为活动阻塞。

进程同步

为什么:
由于进程的异步性,也会给系统造成混乱,在OS中引入进程同步。
任务:
使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。

进程同步的基本概念

  • 两种形式的制约关系:1)间接相互制约关系。由于资源共享 2)直接相互制约关系。主要由于进程间的合作。
  • 临界资源 一次仅允许一个进程访问的资源为临界资源 。
  • 临界区 把在每个进程中访问临界资源的那段代码称为临界区。
  • 同步机制规则 :1)空闲让进 2)忙则等待 3)有限等待 4)让权等待

硬件同步机制

利用计算机硬件指令解决临界区问题
对临界区管理将标识看做一个锁,“锁开”进入,“锁关”等待。 初始打开,每个进入临界区的进程必须对锁进行测试。 测试和关锁操作必须连续(原子操作)
方法:

  • 关中断
  • 利用Test-and-Set指令实现互斥
  • 利用Swap指令实现进程互斥

优点:

  • 适用于任意数目的进程,在单处理器或多处理器上
  • 简单,容易验证其正确性
  • 可以支持进程内存在多个临界区,只需为每个临界区设立一个布尔变量

缺点:

  • 等待要耗费CPU时间,不能实现“让权等待”
  • 可能“饥饿”:从等待进程中随机选择一个进入临界区,有的进程可能一直选不上

信号量机制

信号量(Semaphores)机制:是一种卓有成效的进程同步工具。

整形信号量

  1. 必须置一次且只能置一次初值,并且初值不能为负数。
  2. 只能执行P、V操作。
  3. 必须成对使用P、V操作:P操作遗漏则不能保证互斥访问,V操作遗漏则不能在使用临界资源之后将其释放;P,V次序不能错误、重复或遗漏。
    整形信号量机制的问题:忙等。
    wait操作中信号量S<=0时,会不停的测试
    未遵循让权等待的原则

记录型信号量

只能用于共享一个临界资源

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef struct{
int value;
struct process_control_block *list;
}semaphore;

wait(semaphore *S){
S->value--;
if(S->value<0)block(S->list);
}
signal(semaphore *S){
S->value++;
if(S->value<=0)wakeup(S->list);
}

信号量的初值:0,1,n三种情况
1:表示临界资源;
0:表示进程间的同步(前驱)关系
n:表示若干个资源

AND型信号量

AND同步机制的基本思想:将进程在整个运行过程中需要的所有资源,一次性全都地分配给进程,待进程使用完后再一起释放。只要尚有一个资源未能分配给进程,其它所有可能为之分配的资源,也不分配给他。
原子操作:要么全部分配到进程,要么一个也不分配。
在wait操作中,增加了一个“AND”条件,故称为AND同步,或称为同时wait操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Swait(S1,S2,···,Sn ) {
while(true){
if( S1≥1 and S2≥1 and…and Sn≥1 ){
for (i = 1 ; i<= n; i++){
Si = Si – 1;
}
break;
}else{
place the process in the waiting queue associated with the first Si found with Si<1, and set the program count of this process to the beginning of Swait operation//将进程置于与在 Si<1 的条件下找到的**第一个** Si 关联的等待队列中,并将此过程的程序计数设置为 Swait 操作的开始
}
}

Ssignal(S1,S2,···,Sn){
for( i = 1; i<= n; i++ ){
Si = Si+1;
Remove all the process waiting in the queue associated with Si into the ready queue//将与 Si 关联的队列中**所有**等待的进程移动到就绪队列中
}
}

信号量集

一般信号量集是指同时需要多种资源、每种占用的数目不同、且可分配的资源(预留下限)还存在一个临界值时的信号量处理
一般信号量集的基本思路就是在AND型信号量集的基础上进行扩充,在一次原语操作中完成所有的资源申请

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Swait(S1,t1,d1,…,Sn,tn,dn)(满足ti≥ di)    
if( S1 ≥t1 &…& Sn≥tn){
for( i =1; i<=n; i++){
Si =Si - di;
}
}else{
Place the executing process in the waiting queue of the first Si with Si<ti and set its program counter to the beginning of the Swait operation//将进程置于与在 Si<ti 的条件下找到的**第一个** Si 关联的等待队列中,并将此过程的程序计数设置为 Swait 操作的开始
}//end if
}//end Swait

Ssignal(S1,d1,···,Sn,dn){
for( i =1; i<= n; i++){
Si = Si + di;
Remove all the process waiting in the queue associated with Si into the ready queue//将与 Si 关联的队列中**所有**等待的进程移动到就绪队列中
}
}

三种特例:

  1. Swait(S,d,d):允许每次申请d个资源。当资源数少于d时,不予分配。
  2. Swait (S,1,1):S>1,记录型信号量。S=1时,互斥型信号量。
  3. Swait(S,1,0),可控开关,当S>=1时,允许进入,S<1时,不能进入。

经典进程的同步问题

生产者——消费者问题

记录型信号量解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void producer( ){
do{

Produce an item in nextp;

wait(empty);
wait(mutex);
buffer(in):=nextp;
in:=(in+1) mod n;
signal(mutex);
signal(full);
}while(TRUE);
}

void consumer{
do{
wait(full);
wait(mutex);
nextc:=buffer(out);
out:=(out+1) mod n;
signal(mutex);
signal(empty);
Consumer the item in nextc;
……
}while(TRUE);
}

AND信号量解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int  in=0, out=0;
item buffer[ n ];
semaphore mutex=1, empty=n, full=0;
void producer( ){
do{

produce an item in nextp;

Swait(empty, mutex);
buffer[in] = nextp;
in = (in+1) % n;
Ssignal(mutex, full);
}while(TRUE);
} //end producer

void consumer{
do{
Swait(full, mutex);
nextc = buffer[out];
out = (out+1) % n;
Ssignal(mutex, empty);
consumer the item in nextc;
}while(TRUE);
}

哲学家进餐问题

几种解决方法:

  1. 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐。
  2. 仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐。
  3. 规定奇数号哲学家先拿他左边的筷子,然后再去拿右边的筷子;而偶数号哲学家则相反。按此规定,将是1、 2号哲学家竞争1号筷子;3、4号哲学家竞争3号筷子。即五位哲学家都先竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一位哲学家能获得两只筷子而进餐

AND信号量解决

1
2
3
4
5
6
7
8
semaphore chopstick[5]={1,1,1,1,1};
do{
……;
think;
Sswait(chopstick[(i+1) % 5],chopstick[i]);
eat;
Ssignal(chopstick[(i+1) % 5],chopstick[i]);
}while(TRUE);

读者——写者问题

记录型信号量解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
semaphore rmutex=1, wmutex = 1;
int readcount = 0;

void reader( ){
do{
wait(rmutex);
if readcount=0 then wait(wmutex);
readcount:=readcount+1;
signal(rmutex);

perform read operation

wait(rmutex);
readcount:=readcount-1;
if readcount=0 then signal(wmutex);
signal(rmutex);
}while(TRUE);
}//end reader

void writer( ){
do{
wait(wmutex)
perform write operation;
signal(wmutex)
}while(TRUE);
}

void main(){
cobegin
reader(); writer();
coend
}

信号量集解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int RN;
Semaphore L=RN, mx=1;
//RN标示同时允许多少读进程存在
void reader( ){
do{
swait(L,1,1);
swait(mx,1,0);

perform read operation;

ssignal(L,1);
}while(TRUE);
}//end reader

void writer( ){
do{
swait(mx,1,1; L,RN,0);
perform write operation;
ssignal(mx, 1);
}while(TRUE);
} //end writer

void main( ){
cobegin
reader(); writer();
coedn
}

进程通信

类型

  • 共享存储器系统 - 基于共享数据结构的通信方式。基于共享存储区的通信方式。
  • 消息传递系统 - 是目前的主要通信方式,信息单位:消息(报文)实现:一组通信命令(原语),具有透明性、同步的实现。实现方式的不同,而分成:
    (1)直接通信方式
    (2)间接通信方式
  • 管道通信系统 - 管道:连接一个读进程和一个写进程之间通信的共享文件。 功能:大量的数据发收。 注意:
    (1)互斥
    (2)同步
    (3)**对方是否存在**
    
  • 客户机服务器系统

消息传递通信的实现方法

  • 直接通信方式
    这是指发送进程利用OS所提供的发送命令,直接把消息发送给目标进程。
    系统提供下述两条通信命令(原语):
    Send (Receiver, message);
    Receive(Sender, message);

  • 间接通信方式
    指进程之间利用信箱的通信方式。发送进程发送给目标进程的消息存放信箱;接收进程则从该信箱中,取出对方发送给自己的消息;消息在信箱中可以安全地保存,只允许核准的目标用户随时读取。
    系统为信箱通信提供了若干条原语,分别用于信箱的创建、撤消和消息的发送、接收等。优点:在读/写时间上的随机性
    信箱分为以下三类:
    (1)私用信箱
    (2)公用信箱
    (3)共享信箱
    在利用信箱通信时,在发送进程和接收进程之间,存在以下四种关系:
    (1)一对一关系。
    (2)多对一关系,客户/服务器交互。
    (3)一对多关系, 广播方式。
    (4)多对多关系。

消息格式

消息头:含控制信息如:收/发进程名,消息长度、类型、编号
消息内容:
定长消息:系统开销小,用户不便(特别是传长消息用户)
变长消息:开销大,用户方便。

消息格式进程同步方式

1)发送和接收进程阻塞(汇合)用于紧密同步,无缓冲区时。
2)发送进程不阻塞,接收进程阻塞(多个)相当于接收进程(可能是多个)一直等待发送进程,如:打印进程等待打印任务。
3)发送/接收进程均不阻塞一般在发、收进程间有多个缓冲区时。

进程运行与监控

Linux进程控制块

task_struct结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pid_t pid;
uid_t uid,euid;
gid_t gid,egid;
volatile long state;
int exit_state;
unsigned int rt_priority;
unsigned int policy;
struct list_head tasks;
struct task_struct *real_parent;
struct task_struct *parent;
struct list_head children,sibling;
struct fs_struct *fs;
struct files_struct *files;
struct mm_struct *mm;
struct signal_struct *signal;
struct sighand_struct *sighand;
cputime_t utime, stime;
struct timespec start_time;
struct timespec real_start_time;

task_struct:进程状态

——volatile long state;
state成员的可能取值如下:

1
2
3
4
5
#define TASK_RUNNING	0  
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define TASK_ZOMBIE 4
#define TASK_STOPPED 8

进程状态切换

task_struct:文件管理

进程的启动

UNIX&Linux中创建进程的方式:

  • 在shell中执行命令或可执行文件由shell进程调用fork函数创建子进程

  • 在代码中(已经存在的进程中)调用fork函数创建子进程,fork创建的进程为子进程,原进程为父进程

  • Linux系统中进程0 (PID=0)是由内核创建,其他所有进程都是由父进程调用fork函数所创建的。进程0在创建子进程(PID=1,init进程)后,进程0就转为交换进程或空闲进程

  • 进程1(init进程)是系统中其他所有进程的共同祖先

fork

#include<unistd.h>头文件定义

1
2
3
/* Clone the calling process, creating an exact copy.
Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */

fork函数被正确调用后,将会在子进程中和父进程中分别返回

  • 在子进程中返回值为0(不合法的PID,提示当前运行在子进程中)
  • 在父进程中返回值为子进程ID(让父进程掌握所创建子进程的ID号)
  • 出错返回-1

子进程是父进程的副本

  • 子进程复制/拷贝父进程的PCB、用户空间(数据段、堆和栈)
  • 父子进程共享正文段(只读)
    父进程继续执行fork函数调用之后的代码,子进程也从fork函数调用之后的代码开始执行为了提高效率,fork后不并立即复制父进程数据段、堆和栈,采用了写时复制机制(Copy-On-Write):当父子进程任意之一要修改数据段、堆、栈时,进行复制操作,并且仅复制修改区域

子进程复制父进程的进程控制块

  • 父进程的文件描述符表被子进程复制,父子进程的同一文件描述符指向同一个文件表
  • 父子进程对同一文件访问基于相同的文件当前位置

父子进程对共享文件的常见处理方式:

  • 父进程等待子进程完成。当子进程终止后,文件当前位置已经得到了相应的更新
  • 父子进程各自执行不同的程序段,各自关闭不需要的文件

vfork函数保证子进程先执行,在它调用exec或者exit之后,父进程才会继续被调度执行(父进程处于TASK_UNINTERRUPTIBLE状态)

进程内存空间布局

  • 命令行参数和环境变量 - 主要用于支撑函数调用 存放参数、局部变量等
  • 堆栈 - 用于动态分配内存
  • 未初始化的数据 - 程序执行之前,将此段中 的数据初始化为0,如 全局变量long sum[1000];
  • 初始化的数据 - 包含了程序中需明确赋 初值的变量,如全局变量 int maxcount=99;
  • 正文 - CPU执行的代码部分,正文 段通常是共享、只读的

进程的运行控制

设置环境变量

设置环境变量的三种方法:

  • putenv - 将环境变量字符串放入环境变量表中
  • setenv - 将指定环境变量的值设置为参数指定值
  • unsetenv - 删除指定的环境变量字符串

exec系列函数

进程调用exec系列函数在进程中加载执行另外一个可执行文件
exec系列函数替换了当前进程(执行该函数的进程)的正文段、数据段、堆和栈(来源于加载的可执行文件),但并不修改PCB!
执行exec系列函数后从加载可执行文件的main函数开始重新执行
exec系列函数并不创建新进程,所以在调用exec系列函数后其进程ID(uid)并未改变,已经打开的文件描述符不变

execl execle execlp execv execve execvp
六个函数开头均为exec,所以称为exec系列函数

  • l:表示list,每个命令行参数都说明为一个单独的参数
  • v:表示vector,命令行参数放在数组中
  • e:表示由函数调用者提供环境变量表
  • p:表示通过环境变量PATH来指定路径,查找可执行文件

进程的监测

终止进程函数

头文件stdlib.h定义:void exit( int status )
头文件unistd.h定义:void _exit (int status )
调用这两个函数均会正常地终止一个进程
调用 _exit 函数将会立即返回内核
调用 exit 函数执行一些预先注册的终止处理函数,执行文件I/O操作的善后工作,使得所有缓冲的输出数据被更新到相应的设备,返回内核

获知子进程状态改变

  • 主动获取 - 调用wait或waitpid函数等待子进程状态信息改变,并获取其状态信息
  • 异步通知 - 当一个进程发生特定的状态变化(进程终止、暂停以及恢复)时,内核向其父进程发送SIGCHLD信号,父进程可以选择忽略该信号,也可以对信号进行处理(默认处理方式为忽略该信号)

僵尸进程:
进程在退出之前会释放进程用户空间的所有资源,但PCB等内核空间资源不会被释放。当父进程调用wait或waitpid函数后,内核将根据情况关闭该进程打开的所有文件。而对于已经终止但父进程尚未对其调用wait或waitpid函数的进程(TASK_ZOMBIE状态),称为僵尸进程。

孤儿进程:
如果 父进程在子进程终止之前终止,则子进程的父进程将变为init进程,保证每个进程都有父进程,由init进程调用wait函数进行善后

wait函数

头文件:sys/wait.h
功能:获取任意子进程的状态改变信息(如果是终止状态则对子进程进行善后处理)
pid_t wait(int *statloc);
参数statloc:用于存储子进程的状态改变信息
若成功返回状态信息改变的子进程ID,出错返回-1
子进程状态改变信息包含了多种类型的信息,可以通过系统提供的宏来快速解析子进程的状态
如:
| 宏 | 功能说明 |
| — | — |
| WIFEXITED(statloc) | 当子进程正常终止时该宏为真,对于这种情况可进一步执行WEXITSTATUS(statloc),获取子进程传递给exit、_exit函数参数的低8位 |
| WIFSIGNALED(statloc) | 当子进程异常终止时该宏为真,对于这种情况可进一步执行WTERMSTG(statloc),获取使子进程终止的信号编号 |
| WIFSTOPPED(statloc) | 当子进程暂停时该宏为真,对于这种情况可进一步执行WSTOPSIG(statloc),获取使子进程暂停的信号编号 |
| WIFCONTINUED(statloc) | 若子进程在暂停后已经继续则该宏为真 |

如果一个进程有几个子进程,那么只要有一个子进程状态改变,wait函数就返回

如何才能使用wait函数等待某个特定子进程的状态改变?

  1. 调用wait,然后将其返回的进程ID和所期望的子进程ID进行比较
  2. 如果ID不一致,则保存该ID,并循环调用wait函数,直到等到所期望的子进程ID为止
waitpid函数

功能:等待某个特定子进程状态改变
pid_t waitpid(pid_t pid, int *statloc, int options);
参数:

  • pid:pid == -1:等待任意子进程状态改变(同wait);pid > 0:等待进程ID为pid的子进程状态改变;pid == 0:等待其组ID等于调用进程组ID的任意子进程;pid < -1:等待其组ID等于pid绝对值的任意子进程
  • statloc:用于存储子进程的状态改变信息
  • options:可以为0,也可以是以下常量:WNOHANG:如果没有任何已经终止的子进程则马上返回, 函数不等待,此时返回值为0;WUNTRACED:用于跟踪调试
    成功返回终止子进程ID,失败返回-1

waitpid可以实现非阻塞的等待操作,有时希望取得子进程的状态改变信息,但不希望阻塞父进程等待子进程状态改变

线程的基本概念

  1. 在一个已有进程中创建一个新线程比创建一个全新进程所需的时间少。
  2. 终止一个线程比终止一个进程花费的时间少。
  3. 线程间切换比进程间切换花费的时间少。
  4. 线程提高了不同的执行程序间通信的效率。同一个进程中的线程共享存储空间和文件,它们无需调用内核就可以互相通信。

线程的引入

引入进程是为了使多个程序能够并发执行,以提高资源利用率和系统吞吐量;
引入线程是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性
进程的两个基本属性

  • 一个可拥有资源的独立单位
  • 一个可调度和分派的基本单位

调度和分派的部分通常称为线程或轻型进程,而资源所有权的部分通常称为进程

线程与进程的比较

从调度性、并发性、系统开销和拥有资源等方面对线程和进程进行比较。
(线程必须在某个进程内执行 一个进程可以包含一个线程或多个线程)

调度

在传统的操作系统中,进程作为拥有资源和独立调度、分派的基本单位。而在引入线程的操作系统中,则把线程作为调度和分派的基本单位,而进程作为资源拥有的基本单位。

并发

在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,使得操作系统具有更好的并发性,从而能更加有效地提高系统资源的利用率和系统的吞吐量。

拥有资源

一般而言,线程自己不拥有系统资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,即一个进程的代码段、数据段及所拥有的系统资源,如已打开的文件、I/O 设备等,可以该进程中的所有线程所共享。

独立性

同一进程中的不同线程共享进程的内存空间和资源。
同一进程中的不同线程的独立性低于不同进程

系统开销

线程的切换只需要保存和设置少量的寄存器内容,不涉及存储器管理方面的操作。
由于一个进程中的多个线程具有相同的地址空间,在同步和通信的实现方面线程也比进程容易。在一些操作系统中,线程的切换、同步和通信都无须操作系统内核的干预。(少)

支持多处理机系统

一个进程分为多个线程分配到多个处理机上并行执行,可加速进程的完成。

线程的属性

  1. 轻型实体
    线程自己基本不拥有系统资源,只拥有少量必不可少的资源:TCB,程序计数器、一组寄存器、栈。
  2. 独立调度和分派的基本单位
    在多线程OS中,线程是独立运行的基本单位,因而也是独立调度和分派的基本单位。
  3. 可并发执行
    同一进程中的多个线程之间可以并发执行,一个线程可以创建和撤消另一个线程。
  4. 共享进程资源
    它可与同属一个进程的其它线程共享进程所拥有的全部资源。

线程的状态

同进程一样,线程之间也存在共享资源和相互合作的制约关系,致使线程在运行时也具有间断性。
线程运行时有以下3种状态:
执行状态:表示线程正获得CPU而运行;
就绪状态:表示线程已具备了各种运行条件,一旦获得CPU便可执行;
阻塞状态:表示线程在运行中因某事件而受阻,处于暂停执行的状态;

线程的组成

每个线程有一个TCB结构,即线程控制块,用于保存自己私有的信息,主要由以下部分组成:

  • 一个唯一的线程标识符;
  • 一组寄存器 :包括程序计数器、状态寄存器、通用寄存器的内容;
  • 线程运行状态:用于描述线程正处于何种运行状态;
  • 优先级:描述线程执行的优先程度;
  • 线程专有存储器:用于保存线程自己的局部变量拷贝;
  • 信号屏蔽:对某些信号加以屏蔽;
  • 两个栈指针:核心栈、用户栈。

进程线程对比

应用功能 线程 进程
创建 pthread_create fork,vfork
退出 pthread_exit exit
等待 pthread_join wait、waitpid
取消/终止 pthread_cancel abort
读取ID pthread_self() getpid()
同步互斥/通信机制 互斥锁、条件变量、读写锁 无名管道、有名管道、信号、消息队列、信号量、共享内存

线程间的同步和通信

▪为使系统中的多线程能有条不紊的运行,系统必须提供用于实现线程间同步和通信的机制。在多线程OS中,通常提供多种同步机制:

  • 互斥锁(mutex) - 互斥锁是一种比较简单的、用于实现进程间对资源互斥访问的机制。 由于操作互斥锁的时间和空间开销都较低,因而较适合于高频度使用的关键共享数据和程序段。
  • 条件变量 - 每一个条件变量通常都与一个互斥锁一起使用。 单纯的互斥锁用于短期锁定,主要是用来保证对临界区的互斥进入。而条件变量则用于线程的长期等待, 直至所等待的资源成为可用的。
  • 信号量机制 - 当某线程需利用信号量来实现同一进程中各线程之间的同步时,可调用创建信号量的命令来创建一私用信号量,其数据结构存放在应用程序的地址空间中。

线程的实现方式

用户级线程

用户级线程仅存在于用户空间中。对于这种线程的创建、撤消、线程之间的同步与通信等功能,都无须内核来实现。
优点:

  • 线程切换不调用内核
  • 调度是应用程序特定的:可以选择最好的算法
  • 可运行在任何操作系统上(只需要线程库),可以在一个不支持线程的OS上实现
    缺点:
  • 当线程执行一个系统调用时,该线程及其所属进程内的所有线程都会被阻塞
  • 多线程应用不能利用多处理机进行多重处理。

内核支持线程

内核支持线程,是在内核的支持下运行的,即无论是用户进程中的线程,还是系统进程中的线程,他们的创建、撤消和切换等,是依靠内核实现的。
优点:

  • 在多处理器系统中,内核能够同时调度同一进程中多个线程并行执行;
  • 如果进程中的一个线程被阻塞了,内核可以调度该进程中的其它线程占有处理器运行,也可以运行其它进程中的线程;
  • 内核支持线程具有很小的数据结构和堆栈,线程的切换比较,切换开销小
  • 内核本身也可以采用多线程技术,可以提高系统的执行速度和效率
    缺点:
    对于线程切换而言,其模式切换的开销较大 在同一个进程中,从一个线程切换到另一个线程时,需要从用户态转到内核态再转到用户态进行,这是因为用户进程的线程在用户态运行,而线程调度和管理是在内核实现的,系统开销较大。

组合方式

用户级线程是在用户空间实现的。所有用户级线程都具有相同的数据结构,它们都运行在一个中间系统上:
运行时系统(又称为线程库)
内核控制线程又称为轻型进程LWP
enter description here

习题

  1. 什么是前趋图?为什么要引入前趋图?
    指一个有向无环图,用于描述进程之间执行的先后顺序

  2. 画出前趋图:S1:a=x+y;S2:b=z+1;S3:c=a-b;S4:w=c+1;
    未命名文件

  3. 为什么要引入进程,会产生什么影响?
    为了使程序并发的执行,并且可以对并发执行的程序加以描述与控制;使程序可以并发执行

  4. 从动态性、并发性和独立性的角度比较进程和程序
    动态性:进程的实质是进程实体的执行过程,具有生命周期。而程序是静态的一组有序指令集。
    并发性:进程可以并发执行。程序没有建立PCB不能并发执行。
    独立性:进程是一个能够独立运行的、独立获得资源的、独立接受调度的基本单位。未建立PCB的程序不能独立参与运行

  5. PCB的作用?为什么说PCB是进程唯一标志
    PCB是进程实体的一部分,PCB使一个程序成为能够独立运行的基本单位,PCB描述进程的基本情况和活动过程,进而控制和管理进程。操作系统是通过PCB来对进程进行控制和管理的。

  6. 进程的三个基本状态转化原因
    有1就绪状态——执行状态:进程调度
    执行状态——就绪状态:时间片完成
    执行状态——阻塞状态:I/O请求
    阻塞状态——就绪状态:I/O完成

  7. 为什么要引入挂起状态,有什么性质?
    有终端用户需求、父进程请求、负荷调节的需要、操作系统的需要;挂起状态进程静止不能被调度

  8. 进程切换时要保存的处理器状态信息有哪些?
    通用寄存器、指令寄存器、程序状态寄存器、用户栈指针

  9. 引起进程创建的主要事件
    用户登录、作业调度、提供服务、应用请求

  10. 引起进程撤销的主要事件
    正常结束、异常结束(越界错、保护错、非法指令、特权指令错、运行超时、等待超时、算数运算错、I/O故障)、外界干扰(操作员或操作系统干预、父进程请求、因父进程终止而终止)

  11. 创建进程时所要完成的主要工作
    申请空白PCB、为新进程分配资源、初始化PCB、插入就绪队列

  12. 引起进程阻塞或被唤醒的主要事件
    请求共享资源失败、等待某种操作、新数据尚未到达、等待新任务

  13. 从调度性、并发性、拥有资源及系统开销方面对比进程与线程
    调度性:线程作为调度和分派的基本单位,而进程作为资源拥有的基本单位。
    并发性:均可并发执行。
    拥有资源:进程是拥有资源的基本单位,线程只拥有必不可少的资源,本身不拥有系统资源,但可以访问隶属资源。
    系统开销:在创建、撤销和切换进程的开销显著大于线程。

  14. 解释用户级线程与内核支持线程
    用户级线程:用户级线程仅存在于用户空间中。对于这种线程的创建、撤消、线程之间的同步与通信等功能,都无须内核来实现。
    内核支持线程:内核支持线程,是在内核的支持下运行的,即无论是用户进程中的线程,还是系统进程中的线程,他们的创建、撤消和切换等,是依靠内核实现的。

处理机调度与死锁

处理机调度的层次

  • 高级调度 - 又称长程调度或作业调度,将外存作业调入内存,创建PCB等,插入就绪队列。用于批处理系统。调度最慢
  • 低级调度 - 又称进程调度或短程调度,决定就绪队列中的那个进程应获得处理机,并将处理机分配给选中的进程。调度最频繁
  • 中级调度 - 又称内存调度,把外存上那些已经具备运行条件的就绪进程重新载入内存。从静止就绪到活动就绪。

处理机调度算法的目标

共同目标:

  • 资源利用率:使系统处理器和资源尽可能忙碌
  • 公平性:为进程合理分配CPU时间,不会发生饥饿
  • 平衡性:为不同类型进程平衡分配资源
  • 策略强制执行:如安全策略可无条件准确执行

批处理系统的目标

  • 平均周转时间短
  • 系统吞吐量高:尽量多地选择短作业运行
  • 处理机利用率高:尽量选择计算量大的作业

分时系统的目标

  • 响应时间快
  • 均衡性:指系统响应时间的长短应与用户所请求服务的复杂性相适应。

实时系统的目标

  • 截至时间的保证:开始截止时间 完成截止时间 硬实时、软实时
  • 可以预测性:对调度结果的可预见性

作业与作业调度

  • 作业 Job:用户提交给系统的一项相对独立的工作。程序+数据+作业说明书
  • 作业步:在作业运行期间,每个作业都必须经过若干个相对独立,又相互关联的顺序加工步骤才能得到结果,每一个加工步骤称为一个作业步,各作业步之间存在着相互联系。
  • 作业流:依次执行的作业步,作业步间非并行的。

作业控制块(JCB)

作业在系统中存在的标志,保存了系统对作业进行管理和调度的全部信息。
通常包含:

  • 作业标识
  • 用户名称
  • 用户账号
  • 作业类型(CPU 繁忙型、I/O 繁忙型、批量型、终端型)
  • 作业状态
  • 调度信息(CPU 繁忙型、I/O 繁忙型、批量型、终端型)
  • 资源需求(预计运行时间、要求内存大小、要求 I/O 设备的类型和数量等)
  • 资源使用情况等

作业运行的三个阶段和三种状态

收容阶段:后备状态
运行阶段:运行状态
完成阶段:完成状态

作业调度的主要任务

  • 接纳多少个作业:太多会影响系统服务质量,如延长周转时间;太少会导致资源利用率和系统吞吐量太低
  • 接纳哪些作业:将哪些作业从外存调入内存,取决于所采用的调度算法

先来先服务(FCFS)和短作业优先(SJF )调度算法

在作业调度中是从后备队列调入内存运行。
在进程调度中则是从就绪队列中选出估计运行时间最短的进程分配处理机使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时,再重新调度。

先来先服务:

既可用于作业调度,也可用于进程调度。有利于长作业(进程),而不利于短作业(进程)。

短作业(进程)优先调度算法SJ(P)F:

是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。
对长作业不利,不能保证紧迫性作业(进程)会被及时处理,根据用户所提供的估计执行时间而定不准确。

优先级调度算法和高响应比优先调度算法

优先级调度算法:
外部赋予作业(进程)相应的优先级,例如以作业的紧迫程度作为优先级。
选择优先级高的进程投入运行。既可用于作业调度算法,也可用于进程调度。

高响应比优先调度算法:
赋予作业动态优先级,优先级随作业等待时间延长而增加,从而使长作业的优先级在等待期间不断增加。
响应比Rp:
enter description here
算法既照顾了短作业,又考虑了作业到达的先后次序,不会使长作业长期得不到服务

进程调度

主要任务

  • 保存处理机的现场信息
  • 按某种算法选取进程
  • 把处理机分配给进程strong text

进程调度机制

enter description here

进程调度方式

非抢占方式:

一旦进程投入运行,除了进程完成或者需要阻塞外,不能剥夺其处理机。
采用这种方式时,引起调度的原因可归结为:

  • 进程运行完毕或因发生某事件而无法继续运行
  • 因I/O请求而阻塞
  • 因通信或者同步而阻塞

抢占方式:

允许根据某种原则,暂停正在执行的进程,重新分配处理机。
使用抢占式的原因:

  • 批处理:防止长进程长期占用CPU,公平
  • 分时:人机交互
  • 实时:紧迫任务的执行
    主要原则
  • 优先权
  • 短进程优先
  • 时间片原则

轮转调度算法(RR)

基于时间片轮转
原理: FCFS策略+时钟中断+时间片原则
时间片太小:利于短作业,但增大调度和上下文切换频率,增大系统开销; 时间片太长:退化为FCFS算法。 时间片合适:略大于一次典型的交互所需的时间,使大多数交互式进程能在一个时间片内完成。
当进程的时间片耗尽或运行完毕,系统将CPU分配给队首进程(或新到达紧迫进程)

优先级调度算法

同样分为非抢占式和抢占式
对于优先级是的设立还分为静态优先权(简单,但低优先权作业可能长期不被调度)和动态优先权(长短兼顾 缺点:需计算 Rp=(等待时间+服务时间)/服务时间 )

多队列调度算法

针对:不同用户的调度策略需求:实时/分时/批处理混合系统
和多CPU单就绪队列的问题:互斥访问导致效率不高
解决办法:
不同类型或者性质的进程组织在不同的队列中
每个CPU和一个队列,分配优化,CPU间队列均衡

多级反馈队列调度算法

设置多个就绪队列,并为各个队列赋予不同的优先级。
优先级愈高的队列的进程的执行时间片就愈小。
新进程首先进入最高优先级的队列。每个队列采用FCFS算法。队列中的进程运行一个时间片后未结束则降级排到下一个队列的末尾。最低优先权队列中的进程则按RR方式运行。
按队列优先级调度。只有比队列的优先级高的队列均空时,才运行该队列中的进程。
特点:长、短作业兼顾,有较好的响应时间

基于公平原则的调度算法

  1. 保证调度算法 - 保证的是绝对运行时间,即启动后在某个时间段内必须获得多少运行时间。 例如N个进程平均分配时间。
  2. 公平分享调度算法 - 按照用户数量平均分配时间,而不是进程间平均分配。

实时调度

实时调度必须满足实时任务对截至时间的要求

实现实时调度的基本条件

  • 就绪时间
  • 开始截止时间和完成截止时间
  • 处理时间
  • 资源要求
  • 优先级

单处理机条件下必须保证处理时间与截至时间之比小于1

实时调度算法的分类

非抢占式

enter description here

  1. 非抢占式轮转调度
  2. 非抢占式优先调度

抢占式

  1. 基于时钟中断的抢占式
  2. 立即抢占式

EDF最早截至时间算法

就绪队列按各任务截止时间的早晚排序;具有最早截止时间的任务排在队列的最前面。

LLF最低松弛度优先算法

松弛度=完成截至时间–剩余运行时间–当前时间
按松弛度排序实时任务的就绪队列,松弛度值最小的任务排在队列最前面

优先级倒置

即高优先级进程(或线程)被低优先级进程(或线程)延迟或阻塞。
主要原因可能是较低优先级任务占用临界资源后未释放而切换任务执行
解决方法:

  • 规定进入临界区后不允许抢占
  • 优先级继承机制(动态优先级),即占用同样资源的低优先级进程继承需要资源的进程的高优先级

死锁

资源问题

  • 可重用性资源(打印机)和消耗性资源(消息)
  • 不可抢占性资源(打印机)

计算机系统的死锁

原因:

  1. 竞争可重用资源、可消耗资源
  2. 进程间推进顺序非法。
    enter description here

定义、必要条件和处理方法

定义:如果一组进程中的每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那么该组进程是死锁的

四个条件:

  1. 互斥条件:指进程对所分配到的资源进行排它性使用 。
  2. 请求和保持条件:指进程已经保持了至少一个资源,但又提出了新的资源请求 。
  3. 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
  4. 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链 。

预防死锁

通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来预防发生死锁。
预防死锁使四个必要条件中的第2、3、4条件之一不能成立

破环条件2

通过:

  • 第一种协议规定开始运行之前,必须一次性申请所需的全部资源
  • 第二种协议规定进程在运行过程中要逐步释放已用资源再请求新资源
  • *优点**:简单、易于实现且很安全。
  • *缺点**:资源被严重浪费,使进程延迟运行。
破环条件3

当一个已经保持了某些资源的进程,再提出新的资源请求而不能立即得到满足时,必须释放它已经保持了的所有资源。待以后需要时再重新申请
缺点:因反复地申请和释放资源,致使进程执行被无限推迟,延长进程周转时间、增加系统开销、降低吞吐量

破环条件4

将所有资源按类型进行线性排队,并赋予不同的序号。 所有进程对资源的请求必须严格按照资源序号递增的次序提出
优点:相比前两种提高了资源利用率和系统吞吐量
缺点:各类资源分配的序号必须相对稳定限制了新设备类型的增加;作业使用顺序与系统规定顺序不同造成资源浪费;增加了程序设计难度。

避免死锁

是在资源的动态分配过程中,用某种方法去防止系统进入不安全状态,从而避免发生死锁。不会事先设置限制
安全状态是指系统能按某种进程顺序,使每个进程都可顺利地完成,称系统处于安全状态。

Dijkstra银行家算法

可利用资源向量Available
最大需求矩阵Max
分配矩阵Allocation
需求矩阵Need
P120

死锁的检测与解除

检测死锁:通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源;
解除死锁:当检测到系统中发生死锁时,须将进程从死锁状态中解脱出来。常用的实施方法是撤消或挂起一些进程。
配套使用

检测:

系统必须保存有关资源的请求和分配信息,根据信息通过资源分配图死锁定理的方法检测死锁

解除:

两种常用方法:抢占资源(使死锁进程抢占其它进程资源以完成进程解除死锁)、终止进程(终止或撤销死锁进程)
其中终止方法可终止所有死锁进程,更好是按付出代价最小算法逐个解除

付出代价最小算法
  • 一种找到付出代价最小的终止顺序,但成本高的算法:

    1. 先从死锁进程组中取出一个,形成第一层终止,若有n个死锁进程,则有n个第一层。
    2. 再从n个第一层中取一个,形成第二层终止,每个第一层又有n-1个第二层终止。
    3. 如此循环,直到解除死锁,将各层的总代价计算,得到最小的终止顺序。
      理解为从最低代价开始依次找到导致死锁的最低代价进程
  • 另一种比较有效的算法:

    1. 找到死锁进程组中,终止代价最小的,将其从死锁进程组中删去。
    2. 再从新的死锁进程组中,找到终止代价最小的,删去。
    3. 如此循环,直到解除死锁。
      理解为一直解除最低代价进程(不判断此时死锁是否由它导致)直到解除死锁

习题

1、假设一个多级反馈队列的实现共有4级,各个队列的时间片长度是1、2、4、6秒,已知当前仅在第一级队列上有一个执行时长为10秒的进程O,在两秒后将有一个执行时长为8秒的任务A到达,请算出任务A的周转时间。
1:10-1=9O
2
4
6

1
2:9-1=8O
4
6
任务A到达
1:8-1=7A
2:
4:8O
6

1:
2:7A
4:8O-4=4O
6

1:
2:7A-2=5A
4:
6:4O

1:
2:
4:5A
6:4O-4=0O完成

1:
2:
4:5A-4=1A
6:

1:
2:
4:
6:1A-1=0A完成

所以答案等于1+4+2+4+4+1=16s

2、简述死锁的必要条件,以及预防死锁方法与必要条件的关系。
四个条件:

  1. 互斥条件:指进程对所分配到的资源进行排它性使用 。
  2. 请求和保持条件:指进程已经保持了至少一个资源,但又提出了新的资源请求 。
  3. 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
  4. 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链

预防死锁通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或几个条件,来预防发生死锁。预防死锁使四个必要条件中的第2、3、4条件之一不能成立:

破环条件2通过:第一种协议规定开始运行之前,必须一次性申请所需的全部资源
第二种协议规定进程在运行过程中要逐步释放已用资源再请求新资源;

破环条件3当一个已经保持了某些资源的进程,再提出新的资源请求而不能立即得到满足时,必须释放它已经保持了的所有资源。待以后需要时再重新申请;

破环条件4将所有资源按类型进行线性排队,并赋予不同的序号。 所有进程对资源的请求必须严格按照资源序号递增的次序提出。

3、在银行家算法中,若出现下述资源分配情况,试问:
| Process | Allocation | Need__ | Available |
|—|—|—|—|
| P0 | 0 0 3 2 | 0 0 1 2 | 1 6 2 2 |
| P1 | 1 0 0 0 | 1 7 5 0 |
| P2 | 1 3 5 4 | 2 3 5 6 |
| P3 | 0 3 3 2 | 0 6 5 2 |
| P4 | 0 0 1 4 | 0 6 5 6 |

(1)该状态是否安全?
安全,先执行P0后按P3、P4、P1、P2顺序即可完成全部进程
(2)若进程 P2 提出请求 Request(1,2,2,2)后,系统能否将资源分配
给它?
能,可按P2、P0、P3、P4、P1执行完成

什么是计算机网络

  • 网络实体视角观察:计算机终端设备、数据转发设备、数据传输链路
  • 网络架构视角观察:网络边缘、接入网、网络核心

网络核心两大功能

  • 路由(routing):决定转发策略(转发路径)
  • 转发(forwarding):作出转发行为

计算机网络分类

按覆盖区域

局域网、园区网、城域网、广域网、空天网

按应用场景

家庭网络、公司/机构网络、无线移动网络、运营商网络、天地一体化信息网络

什么是互联网(internet)

从服务视角

  • 作为基础设施为应用提供服务
  • 以提供编程接口方式提供服务

从结构角度

互联网:网络的网络
即:多级ISP分层网络
enter description here

网络数据传输方式

  • 电路交换
  • 分组交换
    (P15~P22)
    共同特点:
    多路复用

不同之处:
电路交换:预留带宽、独占资源
分组交换:存储 转发、数据包形式(共享带宽、竞争资源)

网络性能评价指标

延迟、丢包、带宽、吞吐量
流量强度流量强调计算
瓶颈链路(水桶短板)如:enter description here

延迟

  • 节点处理延迟
  • 排队延迟
  • 传输延迟(发送延迟)
  • 传播延迟
    (P25~P27)

丢包

  • 排队缓冲队列溢出
  • 物理链路截断

带宽

单位bps
即物理链路理论上能承载的最大吞吐量

吞吐量

单位bps/pps

  • 瞬时吞吐量(信息传输速率)
  • 平均吞吐量(信息传输速度)

网络通信协议

通信需要规则,协议建立规则(信息内容组织格式、信息交互顺序逻辑、信息收发处理逻辑)
互联网协议由Internet标准化组织定义
如:

  • IEEE 电气与电子工程师协会(Institute of Electrical and Electronics Engineers)
    的IEEE 802.3(局域网标准)等
    
  • IETF 国际互联网工程任务组(The Internet Engineering Task Force)
    RFC 791(IP)
    

网络协议分层参考模型

enter description here

为什么要分层

  • 处理复杂系统明确结构关系
  • 模块化便于系统维护和更新
  • 网络本身具有复杂异构性
  • 网络技术在高速更新迭代

模型的价值

  • 网络体系结构清晰,各个层级功能明确
  • 层次之间接口明确,方便层内技术演进
  • 层次内部协议统一,支持厂商互联互通

攻击威胁下的网络

常见攻击方式

  • 植入恶意软件(专门用于 损坏、破坏、窃取数据、主机或网络 或 对数据、主机或网络进行非法操作 的代码或软件,如病毒、蠕虫、特洛伊木马)
  • 攻击服务器和网络基础设施
  • 嗅探分组
  • 伪装
  • 修改或删除报文

更多见第八章