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

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

教材学习内容总结

  • 异常是异常控制流的一种形式,他一部分由硬件实现,一部分由操作系统实现。

控制流:控制转移序列。

控制转移:从一条指令到下一条指令。

异常控制流:现代操作系统通过使控制流发生突变来对系统状态做出反应,这些突变称为异常控制流。

异常的剖析,如下图所示:
image

  • 异常的类别——中断、陷阱、故障和终止

image

a)中断处理:异步是指硬件中断不是由任何一条指令造成的,而是由外部I/O设备的事件造成的。

image

b)陷阱和系统调用:系统调用是一些封装好的函数,内部通过指令int n实现。
陷阱最重要的用途是提供系统调用。系统调用运行在内核模式中,并且可以访问内核中的栈。
系统调用的参数是通过通用寄存器而不是栈来传递的,如,%eax存储系统调用号,%ebx,%ecx,%edx,%esi,%edi,%ebp最多存储六个参数,%esp不能用,因为进入内核模式后,会覆盖掉它。

image

c)故障

image

d)终止

image

进程和并发

并发:

image

  1. Concurrency,是并发的意思。并发的实质是一个物理CPU(也可以多个物理CPU)在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。

  2. 微观角度:所有的并发处理都有排队等候,唤醒,执行等这样的步骤,在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根据优先级的不同,而先后进入队列排队等候执行。

  3. 宏观角度:多个几乎同时到达的请求(或线程)在宏观上看就像是同时在被处理。

  4. 通俗点讲,并发就是只有一个CPU资源,程序(或线程)之间要竞争得到执行机会。图中的第一个阶段,在A执行的过程中B,C不会执行,因为这段时间内这个CPU资源被A竞争到了,同理,第二个阶段只有B在执行,第三个阶段只有C在执行。其实,并发过程中,A,B,C并不是同时在进行的(微观角度)。但又是同时进行的(宏观角度)。

进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

image

1)就绪状态
当进程已分配到除CPU以外的所有必要资源后,只要再获取CPU,便可立即执行,进程这时的状态称为就绪状态。一个系统中处于就绪状态的进程可能有多个,通常将它们排成一个队列,称为就绪队列。

2)执行状态
进程已获得CPU,其程序正在执行。在单位处理机系统中,只有一个进程处于执行状态;在多处理机系统中,则有多个进程处于执行状态。

3)阻塞状态
正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即进程的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。
致使进程阻塞的典型事件有:请求I/O,申请缓冲区空间等。也有阻塞队列。

4)挂起状态

5)创建状态
为新进程创建PCB,并填写必要的管理信息 --> 将该进程插入就绪队列中

6)终止状态
当一个进程到达了自然结束点,或是出现了无法克服的错误,或是被操作系统所终结,或是被其他有终止权的进程所终结,它将进入终止状态。进入终止状态后不能再执行,但在操作系统中依然保留一个记录,其中保存状态码和一些计时统计数据,供其他进程收集。一旦其它进程完成了对终止状态进程的信息提取之后,操作系统将删除该进程。

状态间的转换:
1)NULL -> 创建
2)创建 -> 活动就绪
3)创建 -> 静止就绪:考虑到系统当前资源状况和性能要求,并不分配给新建进程所需资源,主要是主存资源,并将其对换到外存,不参与调度,此时进程创建工作尚未完成。
4)执行 -> 终止
5)活动就绪 -> 静止就绪:当进程处于未被挂起的就绪状态时,称此为活动就绪状态,表示为Readya。当用挂起原语Suspend将该进程挂起后,改进程便转变为静止就绪状态,表示为Readys,处于Readys状态的进程不再被调度执行。
6)活动阻塞 -> 静止阻塞:当进程处于未被挂起的阻塞状态时,称它是处于活动阻塞状态,表示为Blockeda。当用Suspend原语将它挂起后,进程便转变为静止阻塞状态,表示为Blockeds。处于该状态的进程在其所期待的时间出现后,将从静止阻塞变为静止就绪。
7)静止就绪 -> 活动就绪:处于Readys状态的进程,若用激活原语Active激活后,该进程将转变为Readya状态。
8)静止阻塞 -> 活动阻塞:处于Blockeds状态的进程,若用激活原语Active激活后,该进程将转变为Blockeda状态。

系统调用:进程控制

  • fork系统调用

        函数作用:创建一个子进程
    
形式:pid_tfork(void);
pid_t vfork(void);

说明: 使用vfork创子进程时,不会进程父进程的上下文

返回值:

[返回值=-1]子进程创建失败

[返回值=0]子进程创建成功

[返回值>0]对父进程返回子进程PID
#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
int main() {
    pid_t id = fork();
    if (id < 0) {
        perror("子进程创建失败!");
    } else {
        if (id == 0) {
            printf("子进程工作:PID=%d,PPID=%d
", getpid(), getppid());
        }else
        {
            printf("父进程工作:PID=%d,PPID=%d,子进程PID=%d
", getpid(), getppid(),id);
            sleep(5);
        }
    }
}

wait函数

  • 通过帮助文档,可以知道其头文件为:
#include <sys/types.h>
#include <sys/wait.h>

exec函数

其实说exec函数在严格意义上来讲是不对的,因为Linux中没有exec函数,而是有6个以exec开头的函数族,exec函数族提供了一个在进程中启动另一个程序执行的方法。

头文件#include <unistd.h>,一共有六个函数族,其中只有execve为系统调用,运行另一个程序,用法为

int execve(const char *filename, char *const argv[],
              char *const envp[]);

理解信号机制

处理方法可以分为三类:

第一种是类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。

第二种方法是,忽略某个信号,对该信号不做任何处理,就象未发生过一样。

第三种方法是,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。

掌握管道和I/O重定向

掌握管道和I/O重定向

在Unix系统中,每个进程都有STDIN、STDOUT和STDERR这3种标准I/O,它们是程序最通用的输入输出方式。几乎所有语言都有相应的标准I/O函数,比如,C语言可以通过scanf从终端输入字符,通过printf向终端输出字符。

Linux 管理的一个最重要并且有趣的话题是 I/O 重定向。此功能在命令行中使你能够将命令的输入输出取自或送到文件中,或者可以使用管道将多个命令连接在一起以形成所谓的“命令管道”。

教材学习中的问题和解决过程

安装信号时对signal()不理解,通过百度发现

第一个参数指定信号的值,第二个参数指定针对前面信号值的处理,可以忽略该信号(参数设为SIG_IGN);可以采用系统默认方式处理信号(参数设为SIG_DFL);也可以自己实现处理方式(参数指定一个函数地址)。如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
传递给信号处理例程的整数参数是信号值,这样可以使得一个信号处理例程处理多个信号。

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigroutine(int dunno)
{ /* 信号处理例程,其中dunno将会得到信号的值 */
        switch (dunno) {
        case 1:
        printf("Get a signal -- SIGHUP ");
        break;
        case 2:
        printf("Get a signal -- SIGINT ");
        break;
        case 3:
        printf("Get a signal -- SIGQUIT ");
        break;
        }
        return;
}
 
int main() {
        printf("process id is %d ",getpid());
        signal(SIGHUP, sigroutine); //* 下面设置三个信号的处理方法
        signal(SIGINT, sigroutine);
        signal(SIGQUIT, sigroutine);
        for (;;) ;
}

收获:对于一个函数类型不太能够理解的话,可以通过分解的方式来理解。

代码调试中的问题和解决过程

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigroutine(int dunno)
{ /* 信号处理例程,其中dunno将会得到信号的值 */
        switch (dunno) {
        case 1:
        printf("Get a signal -- SIGHUP ");
        break;
        case 2:
        printf("Get a signal -- SIGINT ");
        break;
        case 3:
        printf("Get a signal -- SIGQUIT ");
        break;
        }
        return;
}
 
int main() {
        printf("process id is %d ",getpid());
        signal(SIGHUP, sigroutine); //* 下面设置三个信号的处理方法
        signal(SIGINT, sigroutine);
        signal(SIGQUIT, sigroutine);
        for (;;) ;
}

在对signal()函数定义时,对它的类型不是能了解导致编译不通过,后通过查阅资料发现。类型可以分开,分解来得以解决。

代码托管

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

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

  • 计划学习时间:XX小时

  • 实际学习时间:XX小时

  • 改进情况:

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

参考资料

原文地址:https://www.cnblogs.com/wang5324/p/7751096.html