1、什么是进程(Process)和线程(Thread)?有何区别?

(1)进程是并发程序在一个数据集合上的一次执行过程,进程是系统进行资源分配和调度的独立单位线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己不拥有任何系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是它可以访问其隶属进程的全部资源。

(2)线程是进程的一个实体,一个进程可以拥有多个线程,多个线程也可以并发执行。一个没有线程的进程也可以看做是单线程的,同样线程也经常被看做是一种轻量级的进程。并且进程可以不依赖于线程而单独存在,而线程则不然。

(3) 与进程的控制表PCB相似,线程也有自己的控制表TCB,但是TCB中所保存的线程状态比PCB表少得多。

进程的作用与定义:是为了提高CPU的执行效率,为了避免因等待而造成CPU空转以及其他计算机硬件资源的浪费而提出来的。

线程的引入:例如,有一个Web服务器要进程的方式并发地处理来自不同用户的网页访问请求的话,可以创建父进程和多个子进程的方式来进行处理,但是创建一个进程要花费较大的系统开销和占用较多的资源。除外,这些不同的用户子进程在执行的时候涉及到进程上下文切换,上下文切换是一个复杂的过程。所以,为了减少进程切换和创建的开销,提高执行效率和节省资源,人们在操作系统中引入了"线程(thread)"的概念。


2.进程的通讯方式

进程间通讯的方式:

  • 管道有命名管道和非命名管道之分,非命名管道只能用于父子进程通讯,命名管道可用于非父子进程,命名管道就是FIFO,管道是先进先出的通讯方式。FIFO是一种先进先出的队列。它类似于一个管道,只允许数据的单向流动。每个FIFO都有一个名字,允许不相关的进程访问同一个FIFO,因此也成为命名管。
  • 消息队列:是用于两个进程之间的通讯,首先在一个进程中创建一个消息队列,然后再往消息队列中写数据,而另一个进程则从那个消息队列中取数据。需要注意的是,消息队列是用创建文件的方式建立的,如果一个进程向某个消息队列中写入了数据之后,另一个进程并没有取出数据,即使向消息队列中写数据的进程已经结束,保存在消息队列中的数据并没有消失,也就是说下次再从这个消息队列读数据的时候,就是上次的数据!!!
  • 信号量, 不能传递复杂消息,只能用来同步
  • 共享内存,只要首先创建一个共享内存区,其它进程按照一定的步骤就能访问到这个共享内存区中的数据,当然可读可写;

几种方式的比较:

  • 管道:速度慢,容量有限
  • 消息队列:容量受到系统限制,且要注意读的时候,要考虑上一次没有读完数据的问题。
  • 信号量:不能传递复杂消息,只能用来同步
  • 共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了一块内存的。


3.线程同步的方式

  • 临界区:通过对多线程的串行化来访问公共资源或者一段代码,速度快,适合控制数据访问
  • 互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以可以保证公共资源不会同时被多个线程访问
  • 信号量:它允许多个线程同一时刻访问同一资源,但是需要限制同一时刻访问此资源的最大线程数目。信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中PV操作相似。
  • 事件(信号):通过通知操作的方式来保持多线程的同步,还可以方便的实现多线程的优先级比较的操作

总结比较: 

  • 互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部是用的话使用临界区会带来速度上的优势并能够减少资源占用量。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。
  • 互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和线程退出。
  • 通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。

4.ThreadLocal和其他同步机制的比较

Threadlocal和其他所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致的分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的索等等。所有这些都是因为多个线程共享了该资源造成的。

Threadlocal就从另一个角度来解决多线程的并发访问,Threadlocal会为每一个线程维护一个和该线程绑定的变量副本,从而隔离了多个线程的数据共享,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

总结:当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序,使程序更加易读、简洁。


5.关于死锁的问题

首先回答死锁的定义,所谓死锁就是一个进程集合中的多个进程因为竞争资源,而造成的互相等待现象

死锁的原因:系统资源不足;多个进程的推进顺序不合理

死锁的必要条件:

  • 互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。
  • 请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。
  • 非剥夺条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。
  • 循环等待条件(Circular wait):系统中若干进程组成环路,改环路中每个进程都在等待相邻进程正占用的资源。

处理死锁的策略:

(1) 死锁预防破坏导致死锁必要条件中的任意一个就可以预防死锁。例如,要求用户申请资源时一次性申请所需要的全部资源,这就破坏了保持和等待条件;将资源分层,得到上一层资源后,才能够申请下一层资源,它破坏了环路等待条件。预防通常会降低系统的效率。

(2) 死锁避免:避免是指进程在每次申请资源时判断这些操作是否安全,例如,使用银行家算法。死锁避免算法的执行会增加系统的开销。

(3) 死锁检测死锁预防和避免都是事前措施,而死锁的检测则是判断系统是否处于死锁状态,如果是,则执行死锁解除策略。

(4) 死锁解除:这是与死锁检测结合使用的,它使用的方式就是剥夺。即将某进程所拥有的资源强行收回,分配给其他的进程。  


两个相关算法:

鸵鸟算法(即无视死锁,不去处理):

该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。

银行家算法

 所谓银行家算法,是指在分配资源之前先看清楚,资源分配后是否会导致系统死锁。如果会死锁,则不分配,否则就分配。

按照银行家算法的思想,当进程请求资源时,系统将按如下原则分配系统资源:

(1) 当一个进程对资源的最大需求量不超过系统中的资源数时可以接纳该进程。

(2) 进程可以分期请求资源,当请求的总数不能超过最大需求量。

(3) 当系统现有的资源不能满足进程尚需资源数时,对进程的请求可以推迟分配,但总能使进程在有限的时间里得到资源。

(4) 当系统现有的资源能满足进程尚需资源数时,必须测试系统现存的资源能否满足该进程尚需的最大资源数,若能满足则按当前的申请量分配资源,否则也要推迟分配。


6.物理地址,逻辑地址,分页,分段

参考 http://www.cnblogs.com/felixfang/p/3420462.html ,有很好的解释。

另附例题:http://blog.csdn.net/lzx_322/article/details/9209157


7.中断和轮询

中断和轮询的特点

  对I/O设备的程序轮询的方式,是早期的计算机系统对I/O设备的一种管理方式。它定时对各种设备轮流询问一遍有无处理要求。轮流询问之后,有要求的,则加以处理。在处理I/O设备的要求之后,处理机返回继续工作。尽管轮询需要时间,但轮询要比I/O设备的速度要快得多,所以一般不会发生不能及时处理的问题。当然,再快的处理机,能处理的输入输出设备的数量也是有一定限度的。而且,程序轮询毕竟占据了CPU相当一部分处理时间,因此,程序轮询是一种效率较低的方式,在现代计算机系统中已很少应用。

  程序中断通常简称中断,是指CPU在正常运行程序的过程中,由于预先安排或发生了各种随机的内部或外部事件,使CPU中断正在运行的程序,而转到为响应的服务程序去处理。

  轮询——效率低,等待时间很长,CPU利用率不高。

  中断——容易遗漏一些问题,CPU利用率高。


8.操作系统的优先级反转

      优先级反转是指一个低优先级的任务持有一个被高优先级任务所需要的共享资源。高优先任务由于因资源缺乏而处于受阻状态,一直等到低优先级任务释放资源为止。而低优先级获得的CPU时间少,如果此时有优先级处于两者之间的任务,并且不需要那个共享资源,则该中优先级的任务反而超过这两个任务而获得CPU时间。如果高优先级等待资源时不是阻塞等待,而是忙循环,则可能永远无法获得资源,因为此时低优先级进程无法与高优先级进程争夺CPU时间,从而无法执行,进而无法释放资源,造成的后果就是高优先级任务无法获得资源而继续推进。

      优先级反转的解决办法:

(1)设置优先级上限:给临界区一个高优先级,进入临界区的进程都将获得这个高优先级,如果其他试图进入临界区的进程的优先级都低于这个高优先级【这里是为了给原来的低优先级任务分配更多的时间片】,那么优先级反转就不会发生。
(2)优先级继承:当一个高优先级进程等待一个低优先级进程持有的资源时,低优先级进程将暂时获得高优先级进程的优先级别,在释放共享资源后,低优先级进程回到原来的优先级别。嵌入式系统VxWorks就是采用这种策略。



9.资源调度算法

(1)实质是资源分配(分配CPU)的方式。

(2)分类

先来先服务算法

思想:总是选择一个最先进入队列的进程,为之分配处理器,一直到进程执行结束或者阻塞而放弃处理机。

特点:属于非抢占式调度。

缺点:

1. 仅考虑进程的等待时间,有利于长进程,不利于短进程。

2. 实时性不好,未考虑进程的紧迫程度。

影响:会导致短进程(执行时间短)等待时间太长,使得短进程的周转时间太长(执行时间 - 到达时间)。

评价:先来先服务算法有利于CPU繁忙型(执行时间长)的进程,而不利于IO繁忙型(执行时间短)的进程。

短作业优先算法

思想:总是先执行运行时间短的进程。

特点:可以是抢占式调度,也可以是非抢占式调度。

缺点:

1. 进考虑进程的运行时间,对长进程不利,会出现长进程饿死现象。

2.实时性不好,未考虑进程的紧迫程度。

3.进程的运行时间是估计值,不能准确衡量短进程。

优点:能有效地降低所有进程的平均等待时间,提高系统的吞吐量。

(体现在数据上,其实就是降低短进程的等待时间,使得进程的平均周转时间和平均等待时间都降低)。

高优先权优先调度算法

思想:总是先执行优先级高的进程。

特点:可以是抢占式调度,也可以是非抢占式调度。

分类:根据获得优先权时间可以分为两类:

1.静态优先权

特点:创建进程时分配。

优点:简单易行,系统开销小。

缺点:不够精确,而且很可能出现优先权低的进程得不到调度的情况(饿死)

2.动态优先权

特点:进程的优先权能够随着进程的推进和等待时间而改变。

典型代表:高响应比优先调度算法。

进程优先级 = 1 + (等待时间 / 要求服务时间)。

优点:折中了短作业优先 + 先来先服务。即照顾短进程,又考虑进程到达的先后顺序,不会使得作业长期得不到服务。

基于时间片的轮转算法

思想:先来先服务 + 时间片轮转。

特点:抢占式调度(执行不完,也得闪人)。

多级反馈队列调度算法

思想:

1.在多个队列间,属于高优先级优先调度。

2.在队列内,属于先来先服务 + 时间片轮转。

特点:抢占式调度

优点:不必知道各个进程需要的执行时间,而且还可以满足各种类型的进程的需要。

硬件设置:

1. 设置多个就绪队列,

2. 在不同的队列间设置不同的优先级,且优先级下降(越下面的队列优先级越小)。

3. 在不同的队列内设置不同的时间片,且时间片上升(越下面的队列中时间片越长)。

工作方式:

1. 新进程进入第一队列末尾,按先来先服务排队等待调度。

2. 能在一个时间片内执行完,则可以直接离开os,不能在时间片执行完,在放入第二队列。...。

3. 若到最后一个队列仍没有执行完,则放到本队列的队尾,继续循环执行。

注意:

1. 当前i-1个队列为空时,才能调度第i个队列的进程

2. 若第i个队列中的进程A正在执行,但是有进程B进入第1个队列,此时进程A被强占了CPU,之后应该放到所在队列的队尾,等待执行。注意,不是放入下一队列