• 2017-2018-1 20155334 《信息安全系统设计基础》第十三周学习总结


    2017-2018-1 20155334 《信息安全系统设计基础》第十三周学习总结

    找出全书你认为最重要的一章,深入重新学习一下,要求:

    完成这一章所有习题
    详细总结本章要点
    给你的结对学习搭档讲解你的总结并获取反馈
    参考上面的学习总结模板,把学习过程通过博客(随笔)发表,博客标题“学号 《信息安全系统设计基础》第十三周学习总结”,博客(随笔)要通过作业提交。

    本周学习是第八章 异常控制流

    第八章 异常控制流

    现代系统通过使控制流发生突变来对某些情况做出反应,我们把这些突变称作异常控制流。

    • 硬件层:硬件检测到的事件会触发控制突然转移到异常处理程序
    • 操作系统层:内核通过上下文转换将控制从一个用户进程转移到另一个用户进程。
    • 应用层:一个进程可以发送信号到另一个进程,而接收者会将控制突然转移到它的一个信号处理程序

    第一节 异常


    异常是控制流中的突变,它一部分是由硬件实现的,另一部分是由操作系统实现的。

    在任何情况下,当处理器检测到有事发生,他就会通过一张叫异常表的跳转表,进行一个间接的过程调用,到一个专门设计用来处理这类事件的操作系统子程序(异常处理程序)。

    当异常处理程序完成处理后,根据引起异常的事件类型,会发生以下情况:
    1. 处理程序将控制返回给当前命令
    2. 处理程序将控制返回给Inext,即如果没有发生异常将会执行的下一条指令
    3. 处理程序终止被中断的程序
    异常的类别:

    • 中断:异步发生,来自处理器外部的I/O设备的信号的结果,将控制返回给下一条指令

    • 陷阱:陷阱是有意的异常,是执行一条指令的结果,最重要的用途:在用户和内核间提供一个像过程一样的接口,叫系统调用

    • 故障:由错误状况引起,可能能够被故障处理程序修正,故障发生时,处理器将控制转移给故障处理程序,如果能够修正,返回引起故障的指令,重新执行指令,否则返回abort例程,终止

    • 终止:是不可恢复的致命错误造成的结果,通常是一些硬件错误,终止示例:将控制返回abort例程

    Linux/IA32系统中的异常

    • Linux/IA32故障和终止:除法错误、一般保护、故障、缺页、机器检查
    • LinuxllA32 系统调用:Linux 提供上百种系统调用,当应用程序想要请求内核服务时可以使用,包括读文件、写文件或是创建一个新进程

    第二节 进程

    在操作系统层:逻辑控制流,私有地址空间,多任务,并发,并行,上下文,上下文切换,调度

    进程就是一个执行中的程序实例
    系统中的每个程序都是运行在某个进程的上下文中的

    进程提供给应用程序的关键抽象:

    • 一个独立的逻辑控制流
    • 一个私有的地址空间

    进程提供给应用程序的关键抽象:

    • 一个独立的逻辑控制流,它提供一个假象,好像我们的程序独占地使用处理器
    • 一个私有的地址空间,它提供一个假象,好像我们的程序独占地使用存储器系统
    逻辑控制流

    一系列的程序计数器(PC)的值,这些值唯一地对应于包含在程序的可执行目标文件中的指令,或者是包含在运行时动态链接到程序的共享对象中的指令,这个PC值的序列就叫做逻辑控制流,或者简称逻辑流
    进程是轮流使用处理器的。每个进程执行它的流的一部分,然后被抢占(暂时挂起),然后轮到其他进程
    对于运行在改程序上下文的其他程序,它看上去在独占的使用处理器

    并发流
    1. 发流:并发流一个逻辑流的执行在时间上与另一个流重叠,叫做并行流
    2. 并发:多个流并发执行的一般现象称为并发
    3. 多任务:多个进程并发叫做多任务
    4. 并行:并发流在不同的cpu或计算机上,叫做并行
    私有地址空间:进程也为每个程序提供一种假象,好像它独占地使用系统地址空间

    运行应用程序代码的进程初始时是在用户模式中的。进程从用户模式变为内核模式的唯一方法是通过异常

    用户模式和内核模式

    需要限制一个应用可以执行的指令以及可访问的地址空间范围来实现进程抽象,通过特定控制寄存器的一个模式位来提供这种机制。

    • 设置了模式位时,进程运行在内核模式中,进程可以执行任何指令和访问任何存储器位置
    • 没设置模式位时,进程运行在用户模式中,进程不允许执行特权指令和访问地址空间中内核区内的代码和数据
      用户程序必须通过系统调用接口间接地访问内核代码和数据
      用户程序的进程初始是在用户模式中的,必须通过中断、故障或陷入系统调用这样的异常来变为内核模式
    上下文切换
    • 上下文切换:操作系统内核使用叫上下文切换的异常控制流来实现多任务。
    • 上下文切换机制:
      • 保存当前进程的上下文
      • 恢复某个先前被抢占的进程被保存的上下文
      • 将控制传递给这个新恢复的进程

    当内核代表用户执行上下文切换时,可能会发生上下文切换
    一般,即使系统调用没有阻塞,内核亦可以决定上下文切换,而不是将控制返回给调用进程

    第三节 系统调用错误处理

    系统级函数遇到错误时,通常返回-1,并设置全局变量 errno

    第四节 进程控制

    1. 获取进程ID

    每个进程都有一个唯一的正数(非零)进程 ID (PID). getpid 函数返回调用进程的 PID。getppid 画数返回它的父进程的 PID (创建调用进程的进程〉
    getpid getppid 函数返回一个类型为 pid_t 的整数值,在 Linux 系统上它在 types.h中被定义为 int

    2. 创建和终止进程

    进程的三种状态:

    • 运行:要么在CPU上执行,要么在等待被执行,且最终被内核调度
    • 停止:进程的执行被挂起,且不会被调度。收到 SIGSTOP 、 SIGTSTP 、 SIDTTIN 、 SIGTTOU 信号,进程停止,收到 SIGCONT 信号,进程再次开始运行
    • 终止:永远停止。原因可能是:收到终止进程的信号,从主程序返回,调用 exit 函数

    fork 函数:

    1. 调用一次,返回两次
    2. 父子进程是并发运行的,不能假设它们的执行顺序。两个进程的初始地址空间相同,但是是相互独立的
    3. 它们还共享打开的文件

    因为有相同的程序代码,所以如果调用 fork 三次,就会有八个进程

    回收子进程

    当一个进程终止时,内核并不立即把它从系统中清除
    相反,进程被保持在一种已终止的状态中,直到被它的父进程回收

    僵死进程:一个终止了但是还未被回收的进程称为僵死进程
    回收子进程的两种方法:1,内核的init进程 2,父进程waitpid函数
    一个进程可以通过调用waitpid函数来等待它的子进程终止或停止

    判断等待集合的成员

    等待集合的成员由参数pid来确定:

    如果pid>0:等待集合是一个单独子进程,进程ID等于pid
    如果pid=-1:等待集合是由父进程所有的子进程组成

    修改默认行为

    将options设置为常量WNOHANG和WUNTRACED的各种组合,修改默认行为:

    • 检查已回收子进程的退出状态——status
    • 让进程休眠
    加载并运行程序

    execve函数加载并运行:

    • 可执行目标文件filename
    • 带参数列表argv
    • 环境变量列表envp
      只有当出现错误时,例如找不到filename,execve才会返回到调用程序,所以,与fork一次调用返回两次不同,execve调用一次并从不返回

    参数中每个指针都指向一个参数串:

    argv[0]是可执行目标文件的名字
    环境变量的列表是由一个类似的数据结构表示的
    envp变量指向一个以null结尾的指针数组,其中每个指针指向个环境变量串,其中每个串都是形如“NAME=VALUE”的名字一值对

    第五节 信号

    底层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。
    其他信号对应于内核或者其他用户进程中较高层的软件事件。

    信号术语

    发送信号的两个不同步骤:

    发送信号:内核通过更新目的进程上下文中的某个状态,发送(递送)一个信号给目的进程。
    发送信号的两个原因:
    内核监测到一个系统事件,比如被零除错误或者子进程终止
    一个进程调用了kill函数,显式地要求内核发送一个信号给目的进程。一个进程可以发送信号给它自己
    接收信号:信号处理程序捕获信号的基本思想
    待处理信号:一个只发出而没有被接收的信号
    一个进程可以有选择性地阻塞接收某种信号
    待处理信号不会被接收,直到进程取消对这种信号的阻塞
    一个待处理信号最多只能被接受一次,pending位向量:维护着待处理信号集合,blocked向量:维护着被阻塞的信号集合

    发送信号

    进程组
    每个进程都只属于一个进程组,进程组是由一个正整数进程组ID来标识的
    getpgrp函数返回当前进程的进程组ID:默认地,一个子进程和它的父进程同属于一个进程组。
    用/bin/kill/程序发送信号 一个为负的PID会导致信号被发送到进程组PID中的每个进程。
    从键盘发送信号:
    作业:表示对一个命令行求值而创建的进程。外壳为每个作业创建一个独立的进程组。
    用kill函数发送信号 :
    进程通过调用kill函数发送信号给其他的进程。父进程用kill函数发送SIGKILL信号给它的子进程。
    用alarm函数发送信号 :
    在任何情况下,对alarm的调用都将取消任何待处理的闹钟,并且返回任何待处理的闹钟在被发送前还剩下的秒数。

    接收信号

    当内核从一个异常处理程序返回,准备将控制传递该进程p时,它会检查进程p的未被阻塞的待处理信号的集合。如果这个集合是非空的,那么内核选择集合中的某个信号k,并且强制p接收信号k。
    进程可以通过使用signal函数修改和信号相关联的默认行为。 唯一例外是SIGSTOP和SIGKILL,它们的默认行为是不能被修改的。

    include

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum,sighandler_t handler);
    //返回:若成功,返回指向前次处理程序的指针;若出错,为SIG_ERR
    signal函数改变和信号signum相关联的行为的三种方法:

    • handler是SIG_ IGN,忽略类型为signum的信号
    • handler是SIG_ DFL,类型为signum的信号行为恢复为默认行为。
    • 否则,handler就是用户定义的函数地址。这个函数称为信号处理程序。

    设置信号处理程序:通过把处理程序的地址传递到signal函数从而改变默认行为。
    捕获信号:调用信号处理程序。
    处理信号:执行信号处理程序。
    因为信号处理程序的逻辑控制流与主函数的逻辑控制流重叠,信号处理程序和主函数并发执行。

    信号处理问题
    • 待处理信号被阻塞;
    • 待处理信号不会排队等待;
    • 注意:不可以用信号来对其他进程中发生的事件计数。
    显式地阻塞和取消阻塞信号

    sigprocmask函数改变当前已阻塞信号的信号。
    how的值:
    SIG_ BLOCK :添加set中的信号到blocked中
    SIG_ UNBLOCK :从blocked中删除set中的信号
    SIG_ SETMASK :blocked = set

    课后作业及实现

    答:进程A和B是互相并发的,就像B和C一样,因为它们各自的执行是重叠的,也就是一个进程在另一个进程结束前开始。进程A和C不是并发的,因为它们的执行没有重叠;A在C开始之前就结束了。

    答:A.这里的关键点是子进程执行了两个prin七f语句。在fork返回之后,它执行了第8行的prin七fe然后它从if语句中出来,执行了第9行的printf语句。下面是子进程产生的输出:printfl:x=2 printf2: x=1

    B.父进程只执行了第9行的printf:printf2: x=0


    答:父进程打印b,然后是c。子进程打印a,然后是c。意识到你不能对父进程和子进程是如何交错执行的做任何假设是非常重要的。因此,任何满足b}c和a -- c的拓扑排序都是可能的输出序列。有四个这样的序列:acbc, bcac, abcc和bacco

    答:A.每次我们运行这个程序,就会产生6个输出行。 B.输出行的顺序根据系统不同而不同,取决于内核如何交替执行父子进程的指令。

    例如:

    unix> ./waitprob1
    Hello
    0
    1
    Bye
    2
    Bye
    

    答:

    答:

    答:只要休眠进程收到一个未被忽略的信号,sleep函数就会提前返回。但是,因为收到一个SIGINT信号的默认行为就是终止进程(见图8-25 ),我们必须设置一个SIGINT处理程序来允许sleep函数返回。处理程序简单地捕获SIGNAL,并将控制返回给sleep函数,该函数会立即返回。


    答:这个程序打印字符串“213",这是卡内基梅隆大学CS:APP课程的缩写名。父进程开始时打印''2'',然后创建子进程,子进程会陷入一个无限循环。然后父进程向子进程发送一个信号,并等待它终止。子进程捕获这个信号(中断这个无限循环),对计数器值(从初始值2)减一,打印''1",然后终止。在父进程回收子进程之后,它对计数器值(从初始值2)加一,打印,''3'',并且终止。

    代码托管

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时
    第一周 75/75 1/1 5/0
    第二周 135/210 1/2 4/9
    第三周 234/444 1/3 6/15
    第四周 486/930 1/4 8/23
    第五周 753/1683 3/7 43/66
    第六周 503/2186 2/9 54/120
    第七周 823/3006 2/11 43/163
    第八周 756/3762 1/12 52/215
    第九周 1120/4882 3/15 63/278
    第十周 420/5302 0/15 32/310
    第十一周 531/5833 2/17 46/356
    第十二周 243/6076 0/17 20/376
    第十三周 359/6435 2/19 42/418

    尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
    耗时估计的公式
    :Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

    参考:软件工程软件的估计为什么这么难软件工程 估计方法

    • 计划学习时间:XX小时

    • 实际学习时间:XX小时

    • 改进情况:

    (有空多看看现代软件工程 课件
    软件工程师能力自我评价表
    )

    参考资料

  • 相关阅读:
    读Android之大话设计模式--前言和说明
    把二叉树打印成多行
    按之字形顺序打印二叉树
    对称的二叉树
    二叉树的下一个结点
    链表中环的入口结点
    字符流中第一个不重复的字符
    表示数值的字符串
    构建乘积数组
    数组中重复的数字
  • 原文地址:https://www.cnblogs.com/bestixx/p/8053415.html
Copyright © 2020-2023  润新知