《现代操作系统》–引论、进程与线程

1.操作系统是管理计算机硬件资源,控制其他程序运行并为用户提供交互操作界面的系统软件的集合。

 

2.多线程不提供真正的并行处理。在一个时刻一个CPU只有一个进程在运行,但是线程的切换时间则减少到纳秒数量级。

 

3.RAM:RamdomAccessMemory易挥发性随机存取存储器,高速存取,读写时间相等,且与地址无关,如计算机内存等。

 

4.ROM:Read Only Memory只读存储器。断电后信息不丢失,如计算机启动用的BIOS芯片。存取速度很低,(较RAM而言)且不能改写。由于不能改写信息,不能升级,现已很少使用。

 

5.在任意一个给定臂的位置,每个磁头可以读取一段环形区域,称为磁道。把一个给定臂的位置上的所有磁道合并起来,责成了一个柱面。每个磁道划分为若干扇区,扇区的典型值是512字节。在现代磁盘中,教外面的柱面比较内部的柱面有更多的扇区。

image

6.总线(Bus)是计算机各种功能部件之间传送信息的公共通信干线,它是由导线组成的传输线束, 按照计算机所传输的信息种类,计算机的总线可以划分为数据总线、地址总线和控制总线,分别用来传输数据、数据地址和控制信号。总线是一种内部结构,它是cpu、内存、输入、输出设备传递信息的公用通道,主机的各个部件通过总线相连接,外部设备通过相应的接口电路再与总线相连接,从而形成了计算机硬件系统。

 

7.BIOS(Basic Input Output System),基本输入输出系统。BIOS通过尝试储存在CMOS储存器中的设备清单决定启动设备。如果系统从硬盘启动,那么启动设备的第一个扇区被读入内存并执行。这个扇面中包含一个对保存在启动扇面末尾的分区表检查的程序,以确定哪个分区是活动的。然后,从该分区读入第二个启动装载模块。来自活动分区的这个装载模块被读入操作系统,并启动之。

 

8.进程本质上是正在执行的一个程序。与每个进程相关的是进程的地址空间。在许多操作系统中,与一个进程有关的所有信息,除了该进程自身地址空间的内容以外,均存放在操作系统的一张表中,称为进程表,进程表是数组(或链表)结构,当前存在的每个进程都要占用其中一项。

 

9.若一个进程能够创建一个或多个进程(称为子进程),而且这些进程又可以创建子进程,则很容易得到进程树。

image

进程A创建两个子进程B和C,进程B创建三个子进程D、E和F

 

10.系统管理器授予每个进程使用一个给定的UID标识,每个被启动的进程都有一个启动该进程的用户UID,子进程拥有与父进程一样的UID,用户可以是某个组的成员,每个组也有一个GID标识。

 

11.进程和文件层次都可以组织成树状结构,但这两种树状结构有不少不同之处。一般进程的树状结构层次不深(很少超过三层),而文件树状结构的层次常常多于四层、五层或更多层。进程树层次结构是暂时的,通常最多存在几分钟,而目录层次则可能存在数年之久。进程和文件在所有权及保护方面也是有区别的。典型的,只有父进程能控制和访问子进程,而在文件和目录中通常存在一种机制,使文件所有者之外的其他用户也可以访问该文件。

 

12.在MS-DOS和windows中,用反斜线( \ )字符作为分隔符,而在UNIX中使用正斜线( / )。

 

13.在UNIX中的另一个重要概念是安装文件系统。在mount调用之前,根文件系统在硬盘上,而第二个文件系统在CD-ROM上,他们是分离的和无关的。mount系统调用允许把CD-ROM上的文件系统连接到程序所希望的根文件系统上。

 

14.管道。管道pipe是一种虚文件,它可连接两个进程。

 

15.UNIX操作系统通过对每个文件赋予一个9位的二进制保护代码,对UNIX的文件实现保护。该保护代码有三个3位字段,一个用于所有者,一个用于所有者同组(用户被系统管理员划分成组)中的其他成员,而另一个用于其他人。每个字段中有一位用于读访问,一位用于写访问,一位用于执行访问。这些位就是知名的rwx位。

 

16.在UNIX中,fork是唯一可以在POSIX创建进程的途径。它创建一个原有进程的精确副本,包括所有的文件描述符,寄存器等全部内容。在fork之后,原有的进程及其副本(父与子)就分开了。在fork时,所有的变量具有一样的值。虽然父进程的数据被复制用以创建子进程,但是其中一个的后续变化并不会影响到另一个。(由父进程和子进程共享的程序正文,是不可改变的)fork调用返回一个值,在子进程中该值为0,并且等于子进程的进程标识符,或等于父进程中PID。使用被返回的PID,就可以在两个进程中看出哪一个是父进程,哪一个是子进程。

    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;

 

17.在UNIX的进程将其存储空间划分为三段:正文段(如程序代码)、数据段(如变量)以及堆栈段。数据段向上增长而堆栈段向下增长。

 

18.在windows中没有类似UNIX中的进程层次,所以不存在父进程和子进程的概念。

 

19.有4种主要事件导致进程的创建:

①:系统初始化

②:执行了正在运行的进程所调用的进程创建系统调用

③:用户请求创建一个新的进程

④:一个批处理作业的初始化

 

20.守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。unix系统有很多守护进程,大多数服务器都是用守护进程实现的。比如,网络服务inetd、Web服务http等。同时,守护进程完成许多系统任务。比如,作业规划进程crond、打印进程lqd等。

 

21.在UNIX和Windows中,进程创建之后,父进程和子进程有各自不同的地址空间。

 

22.以下条件会引起进程的退出:

①:正常退出(自愿的)

②:出错退出(自愿的)

③:严重退出(非自愿)

④:被其他进程杀死(非自愿)

 

23.windows中没有进程层次概念,所有的进程都是地位相同的。创建进程的时候,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程。但是他有权把这个令牌传送给某个其他进程,这样就不存在进程层次了。在UNIX中,进程就不能剥夺其子女的“继承权”。

 

24.进程的三种状态:

①:运行态(该时刻进程实际占用CPU)

②:就绪态(可运行,但因为其他进程正在运行而暂时停止)

③:阻塞态(除非某种外部事件发生,否则进程不能运行)

状态转换图

1:就绪->执行, 调度程序选择这个进程
2:执行->就绪, 调度程序选择另一个进程

3:执行->阻塞, 进程为等待输入而阻塞

4:阻塞->就绪, 出现有效输入

 

25.为了实现进程模型,操作系统维护着一张表格(一个结构数组),即进程表。每个进程用一个进程表项。(有些作者称这些表项为进程控制块)。该表项包含了进程状态的重要信息,包含程序计数器、堆栈指针、内存分配状况、所打开文件的状态、账号和调度信息、以及其他在进程由运行状态转换到就绪态或阻塞态时必保存的信息。

image

 

26.进程中不同的线程不像不同的进程一样有很大的独立性,所有的线程都有完全一样的地址空间。线程也有运行、阻塞、就绪或终止状态。每一个线程都有自己的堆栈。常见的线程调用时thread_yield,它运行线程自动放弃CPU从而让另一个线程运行。

 

27.在用户空间实现线程和在内核中实现线程:

imageimage

线程表的位置:一个在进程中、一个在内核。

 

28.信号是给进程的而不是给线程的。

 

29.一个消息的到达导致系统创建一个处理该消息的线程,这种线程称为弹出式线程。

 

30.进程间通信:

1.竞争条件:即两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,称为竞争条件。

2.临界区:

互斥:即以某种手段确保当一个进程在使用一个共享变量或文件时,其他进程不能做同样的操作。

我们把对共享内存进行访问的程序片段称作临界区域或临界区。

为了避免对临界区的竞争条件,保证使用共享数据的并发进程能够正确和高效的进行协作,一个好的解决方案,必须满足:

①:任何两个进程不能同时处于其临界区

②:不应对CPU的速度和数量做任何假设

③:临界区外运行的进程不得阻塞其他进程

④:不得使进程无限期等待进入临界区

image

31.忙等待的互斥

1.屏蔽中断

屏蔽中断后CPU将不会被切换到其他进程,于是,一旦某个进程屏蔽中断之后,它就可以检查和修改共享内存,而不必担心其他进程进入。屏蔽中断只对执行disable指令的CPU有效,其他CPU仍将继续运行。

2.锁变量

当一个进程想进入其临界区时,它首先测试这把锁。如果该锁的值为0,则该进程将其设置为1并进入临界区。若这把锁的值已经为1,则该进程将等待直到其值为0.于是,0就表示临界区内没有进程,1表示已经有某个进程进入临界区。这种方法同样会发生竞争条件。

3.严格轮换法

连续测试一个变量直到某个值出现为止,称为忙等待。只有在有理由认为是非常短的情况下,才使用忙等待,用于忙等待的锁,称为自旋锁。

4.Peterson解法

代码1

5.TSL指令

TSL RX,LOCK    测试并加锁,执行TSL指令的CPU将锁住内存总线,以禁止其他CPU在本指令结束之前访问内存。

114333711

 

32.睡眠与唤醒

忙等待不仅浪费了CPU时间,而且还可能引起预想不到的结果。考虑一台计算机有两个进程,H优先级高,L优先级较低。调度规则规定,只要H处于就绪态它就可以运行。在某一时刻,L处于临界区中,此时H变到就绪态,准备运行。现在H开始忙等待,但由于当H就绪时L不会被调度,也就无法离开临界区,所以H将永远忙等待下去,这种情况有时被称作优先级反转问题

最简单的是sleep和wakeup。sleep是一个将引起调用进程阻塞的系统调用,即将被挂起,直到另外一个进程将其唤醒。wakeup调用有一个参数,即要被唤醒的进程。另一种方法是让sleep和wakeup各有一个参数,即有一个用于匹配sleep和wakeup的内存地址。

 

33.生产者-消费者问题

image

 

34.信号量:信号量是最早出现的用来解决进程同步与互斥问题的机制(也可实现进程通信),包括一个称为信 号量的变量及对它进行的两个原语操作。信号量为一个整数,我们设这个信号量为:sem。很显然,我们规定在sem大于等于零的时候代表可供并发进程使用的 资源实体数,sem小于零的时候,表示正在等待使用临界区的进程的个数。根据这个原则,在给信号量附初值的时候,我们显然就要设初值大于零。

首先应弄清PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:

             P(S):①将信号量S的值减1,即S=S-1;

                    ②如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。

             V(S):①将信号量S的值加1,即S=S+1;

                    ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。

PV操作的意义:我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

使用PV操作实现进程互斥时应该注意的是:

(1)每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。

(2)P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。

(3)互斥信号量的初值一般为1。

利用信号量和PV操作实现进程同步:

PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。

信号量、PV操作是解决进程间的同步与互斥问题的。

★     做题时尤其要注意隐藏的同步、互斥问题。这些问题通常可以归入生产者-消费者问题和阅读者-写入者问题。

★     PV操作一定是成对出现的,但是这不意味着它会在一个进程内成对出现。

★     在互斥关系中,PV操作一定是在一个进程内成对出现。而且,信号一定大于0,具体多少视情况而定。而对于同步关系,则一对PV操作在两个进程或者更多的进程中出现。

★     对于同步关系,信号量可能为0,也可能不为0;用于同步的信号个数可能1个,也可能是多个。

★     在生产者-消费者问题中,要设置三个信号量:empty-空闲的缓存区数量,初值为n;full-已填充的缓存区数量,初值为0;mutex-保证只有一个进程在写入缓存区,初值为1。

★     在阅读者-写入者问题中,设置两个信号量:信号量access-控制写入互斥,初值为1;信号量rc-控制对共享变量ReadCount(读者统计值)的互斥访问。

 

35.互斥量:互斥量表现互斥现象的数据结构,也被当作二元信号灯。一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源。

Mutex 本质上说就是一把锁,提供对资源的独占访问,所以Mutex主要的作用是用于互斥。Mutex对象的值,只有0和1两个值。这两个值也分别代表了 Mutex的两种状态。值为0, 表示锁定状态,当前对象被锁定,用户进程/线程如果试图Lock临界资源,则进入排队等待;值为1,表示空闲状态,当前对象为空闲,用户进程/线程可以 Lock临界资源,之后Mutex值减1变为0。

Mutex可以被抽象为四个操作:

– 创建 Create

– 加锁 Lock

– 解锁 Unlock

– 销毁 Destroy

Mutex被创建时可以有初始值,表示Mutex被创建后,是锁定状态还是空闲状态。在同一个线程中,为了防止死锁,系统不允许连续两次对Mutex加锁(系统一般会在第二次调用立刻返回)。也就是说,加锁和解锁这两个对应的操作,需要在同一个线程中完成。

 

互斥量值只能为0/1,信号量值可以为非负整数。

互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。

 

36.条件变量:与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止通常条件变量和互斥锁同时使用。

条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。

条件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量可以被用来实现这两进程间的线程同步。

 

37.管程:管程的基本思想是,将共享变量和对它们的操作集中在一个模块中,操作系统或并发程序就由这样的模块构成。这样模块之间联系清晰,便于维护和修改,易于保证正确性。
    从语言的角度看,管程主要有以下特性:
  (1)模块化。管程是一个基本程序单位,可以单独编译;
  (2)抽象数据类型。管程是中不仅有数据,而且有对数据的操作;
  (3)信息掩蔽。管程外可以调用管程内部定义的一些函数,但函数的具体实现外部不可见;
    对于管程中定义的共享变量的所有操作都局限在管程中,外部只能通过调用管程的某些函数来间接访问这些变量。因此管程有很好的封装性。管程通常是用于管理资源的,因此管程中有进程等待队列和相应的等待和唤醒操作。

 

38.消息传递:这种进程间通信的方法使用两条原语send和receive,他们像信号量而不像管程,是系统调用而不是语言成分。因此可以很容易将他们加入到库例程中去,如:

send(destination, &message);         和          receive(source, &message);

消息传递设计:一旦接受到信息,接收方马上回送一条特殊的确认消息,如果发送方在一段时间内未收到确认,则重发信息。

 

39.调度:在操作系统中,完成选择工作的这一部分称为调度程序,该程序使用的算法称为调度算法。

某些进程花费了绝大多数时间在计算上,而其他进程则在等待I/O上花费了绝大多数时间。前者称为计算密集型,后者称为I/O密集型。

两类调度算法:

非抢占式调度算法:挑选一个进程,然后让该进程运行直至被阻塞(阻塞在I/O上或等待另一个进程),或者直至该进程自动释放CPU。

抢占式调度算法:挑选一个进程,并且让该进程运行某个固定时段的最大值。如果在该时段结束时,该进程仍在运行,他就会被挂起,而调度算法会选择另一个进程运行。

调度算法分类:

批处理,交互式,实时

 

吞吐量:是系统每小时完成的作业数量。

周转时间:是指从一个批处理作业开始直到作业完成时刻为止的统计平均时间。

 

批处理系统中的调度:

1.先来先服务:以队列的形式,先来的作业先执行。

2.最短作业优先:预测最短的作业然后选择最短的作业先运行。

3.最短剩余时间优先:当前剩下时间最少的先运行。

 

交互式系统中的调度:

1.轮转调度:每个进程被分配一个时间片,时间片结束时,若还在运行,则分配给另一个进程。

时间片设得太短会导致过多的进程切换,降低了CPU效率,而设得太长又可能引起对短的交互请求的响应时间变长。将时间片设为20ms-50ms通常是一个比较合理的折中。

2.优先级调度:优先级高的可运行进程先运行。调度程序会在每个时钟滴答(即每个时钟中断)降低当前进程的优先级。

3.多级队列:设立优先级类。属于最高优先级的进程运行一个时间片,属于次高优先级类的进程运行2个时间片,再次一级运行4个时间片,依次类推。当一个进程用完分配的时间片后,它被移到下一类。

4.最短进程优先:优先运行可运行进程中最短的那个进程。

5.保证调度:若所有进程都等价,则每个进程获得1/n的CPU时间。

6.彩票调度:向进程提供各种系统资源的彩票,一旦要做出决策时,随机抽出一张彩票,拥有该彩票的进程获得该资源。

7.公平分享调度:不考虑用户,每个进程都将获得等价的CPU时间片。

 

用户级线程和内核级线程之间的差别在于性能,用户级线程的线程切换需要少量的机器指令,而内核级线程需要完整的上下文切换。

 

转载请注明来源:www.blogfshare.com  By:AloneMonkey

本文链接:http://www.alonemonkey.com/operating-system-one.html