1. 进程与线程
1) 进程概念:由程序和代码、进程空间、系统资源、栈区组成,为对进程管理,通过PCB实现。
2) 进程的状态和转换:创建,就绪,运行,阻塞,结束。
① 由空到创建:第一个进程有系统初始化产生,以后有父进程通过创建进程的系 统调用产生。
② 创建到就绪:创建完成后,进入就绪状态。
③ 就绪到运行:被调度程序选中,分配到处理机上执行。
④ 运行到结束:调用结束进程系统调用或者异常流产,进行结束。
⑤ 运行到就绪:时间片到或者被高优先级进程打断
⑥ 运行到等到:通过系统调用,请求某种资源,未得到,处于等待状态;系统调用是目态到管态的过程。
⑦ 等待到就绪:等待的事件来临
3) 进程控制:
① 进程创建与终结:主要有初始化PCB表,置进程为就绪状态。
② 模式切换:两种模式,目态和管态;划分的理由是保护操作系统和操作系统的数据表格不被可能出错的程序破坏。从管态到目态是通过操作系统内核程序修改程序状态字实现,从目态到管态是通过异常(也叫自陷、例外、内中断,不可屏蔽,有指令出错或者缺页触发)或者外中断(有硬件产生,可屏蔽)。(内中断和外中断,统称中断);进程从目态到管态,只需保存进程的处理机信息。进行切换,要保存进程空间信息。
③ 进程切换:保存处理机信息,修改进程控制块,修改存储管理数据。
4) 作业与进程的关系
① 批处理系统中作业与进程的关系:由SPooling输入进程将作业放入输入井,成为后备作业,由作业调度程序选择后备作业,创建根进程;可以有根进程创建更多的子进程,共同完成作业,由作业终止程序终至完成的作业,随后将作业送入输出井,有输出进程把数据送入打印机。
② 分时系统中作业与进程的关系:用户通过命令语句逐条地与系统应答式地输入命令,提交作业步骤。
③ 交互式地提交批作业:系统有专门的调度程序,负责从作业队列中,选取作业,为选取的作业创建根进程,执行作业说明书中的命令.
5) 进程通信,方法:共享存储方法(需要进行pv操作,由于进程空间相对独立的,因此要通过特殊的系统调用实现);消息传递方式(通过发送和接受原语实现通信)
6) 多线程概念与多线程模型:进程只作为除cpu以外的资源;线程则作为处理机的分配单位。
2. 处理机调度
1) 调度的基本概念
① 高级调度:从外存上等候调度的作业中,选择一个调入内存,分配资源,创建进程,挂到就绪队列上。
② 中级调度:把暂时无法运行的进程调入外存,减少内存空间的浪费;等内存空间空闲,把外存有条件的进程重新调入内存。引入中级调度,主要提高内存使用率和提高系统的吞吐量。调度出去的进程为挂起状态;中级调度实质为兑换。
③ 低级调度:进程调度。
2) 进程调度的方式:
① 剥夺式调度:有优先级原则,时间片原则。
② 非剥夺式调度:除进程运行结束或者进入阻塞状态以外,进程一直占用处理机。
3) 进程主动放弃处理机的原因有:
① 进程执行完毕
② 进程进入阻塞状态
4) 在可剥夺的进程调度中,新就绪的进程会按照某种原则,剥夺正在运行的进程的处理机,进程申请调度的时机,有以下情况:
① 中断处理完毕,引起某个进程变成就绪状态。
② 进程释放临界区,引起等待该临界区的进程就绪
③ 当进程发生系统调用,引起某个时间发生,导致其他等待进程就绪。
④ 引起其他任何原因导致进程为就绪态时。
总之,当有新进程就绪时,引发进程调度的申请。
5) 在可剥夺式进程调度系统中,即便没有新的就绪进程,为了使所有就绪进程占用处理机,可在下述情况下申请进程调度:
① 时钟中断发生,时间片到,其他进程请求调度。
② 任何引起优先级发生变化时,应请求重新调度。
操作系统并不一定要在引发进程调度原因时,马上进行进程调度。
6) 进程的调度、切换、时机:一般来说,请求调度--->调度----->切换,三个事件应该一气呵成;但在现在操作系统中,不能进行进程的调度与切换的情况有:
① 处理中断过程中。
② 进程在操作系统那内核临界区中。
③ 其他需要完全屏蔽中断的原子操作过程中。
在上述的过程中,引发调度的条件,并不能马上进行调度,系统只是设置请求调度标志,等走出上述过程后,才进行调度和切换。应当进行进程调度和切换的时机如下:
<1>,发生引起调度事件,且当前进程进入阻塞状态,可马上进行调度(若os只有在这种情况下进行调度,说明os是非剥夺调度。)
<2>,当中断处理结束或者自陷处理结束后,返回被中断进程的用户态程序现场前,若置上请求调度标志,即可马上进行调度与切换。(实现了剥夺式调度)
切换往往是在调度之后发生的;典型的进程切换需要保存原进程当前切换点的现场信息,恢复被调度进程的现场信息。现场信息有:PC,PS,其他寄存器的内容、内核栈指针,进程存储空间的指针。
为了进行进程现场切换,操作系统内核将原进程的上述信息推入当前进程的内核栈保存它们,并跟新堆栈指针。内核从新进程的内核栈中装入新进程的现场信息,还要更新当前进程空间的指针,并且作废处理机联想存储器中有关原进程的信息。在内核完成清除工作后,重新设置PC寄存器,控制转到新进程的程序,开始运行。
7) 调度的基本准则:
① 从用户角度:周转时间段,响应时间短,截止时间的保证
② 从系统角度:吞吐量达;处理机利用率高;各类资源平衡利用。
8) 调度算法:
① 先来先服务调度算法(可不剥夺式调度)
② 优先级调度算法,两种,非可剥夺式优先级调度算法和可剥夺式优先级调度算法。
③ 时间片轮转算法发:先采用先来先服务,然后时间片到,把进程挂到就绪队列的末尾。时间片太大,那么将退化为先来先服务算法;若时间片太小,那么切换过于频繁,处理机开销变大,效率降低。
④ 短进行优先调度:优先选择运行时间短的小进程。(不可剥夺方式)
短进程优先算法和先来先服务算法都是非剥夺的,因此不能用于分时系统中,这是因为不能对用户及时响应。
⑤ 最高响应比优先算法:对短进程优先的改进,属于非可剥夺式算法。按照此算法,每个进程都有一个优先数,该优先数不但是要求的服务时间的函数,而且是该进程得到的服务所花费的等待时间的函数。进程的动态优先计算公式:优先数 = (等到时间+请求服务时间)/(情感求服务时间),请求服务时间是分母,故对短进程有利,他的优先数高,可以优先运行。但由于等待时间是分子,故长进程等待较长的时间,从而提高其调度优先数,被分给了处理机。进程一旦得到锤击,他就一直运行到进程完成,中间不被抢占。可以看出“等待时间+请求服务时间”就是系统对作业的响应时间。
⑥ 多级反馈队列调度算法:采用多级队列,每级队列的优先级不同,优先级大的队列,时间片短。除最后一级别采用时间片轮转法后,其他的队列采用先进先出算法。
3. 进程同步
1) 同步关系,互斥关系;临界资源;临界区
2) 实现临界段问题的硬件方法:
① 屏蔽中断
② Test_and_set指令
③ Swap指令
④ 信号量
⑤ 管程:由一组同步变量和使用同步变量的过程组成;是更高级的同步与互斥的抽象,但其解决同步与互斥的能力低于信号量机制。
4. 死锁:在一个进程集合里面,若每个进程都在等待某些释放资源的时间的发生,而这些事件又必须有这个进程集合中的某些进程产生,就成这些集合处于死锁状态。
1) 死锁条件:
① 互斥。必须需要使用互斥的资源
② 占用等待。
③ 非剥夺
④ 循环等待
2) 死锁处理策略:
① 死锁防止:通过应用编程或者资源设计破坏死锁条件。
② 死锁避免:分配资源时,通过判断如果满足这次资源分配后,仍存在一条路径,使系统不会进入死锁状态,如果没有这种路径,则拒绝分配。
3) 死锁防止:
① 破坏互斥条件
② 破坏占有等待条件
③ 破坏非剥夺条件
④ 破坏循环等待条件
4) 死锁避免:银行家算法
5) 死锁检测与解除:
① 检测:定时运行死锁检测程序。
② 解除:删除某个进程,释放资源。
信号量机制相关代码:
//整型信号量
wait(S)
{
while(S<=0);
S--;
}
signal(S)
{
S++;
}
由于整型信号量不满足进程同步的第四个原则“让权等待”;当wait操作时若信号量S<=0,那么就会不断的循环测试S的值,不会释放CPU,记录型信号量可以解决这个问题:
// 记录型信号量
typedef struct
{
int value;
struct process * L;
}semaphore;
void wait(semaphore S)
{
S.value--;
if(S.value<0)
{
add this process to S.L;
block(S.L);
}
}
void signal(semaphore S)
{
S.value++;
if(S.value<=0)
{
remove a process P from S.L;
wakeup(P);
}
}
以下举出几个经典的同步问题:
1,生产者消费者问题
问题描述:生产进程和消费进程共享大小为n的缓冲区,只要缓冲区没有满,生产者就可以把产品放入缓冲区;只要缓冲区不空,消费者就可以从缓冲区中取出消息。
Semaphore mutex = 1;
Semaphore empty = n;
Semaphore full = 0;
producer()
{
while(1)
{
make a product;
wait(empty);
wait(mutex);
add a product to buffer;
signal(mutex);
signal(full);
}
}
consumer(){
while(1)
{
wait(full);
wait(mutex);
remove a product from buffer;
signal(mutex);
signal(empty);
}
}
2,读者写者问题
问题描述:若干个读者和一个写着共享一个文件,写着在这个文件上写的时候不允许有读者读,党读者在读这个文件的时候,不允许写。
int count = 0; //记录读者的数量
semaphore mutex = 1; //更新cout变量用
semaphore rw = 1; //读者和写着互斥访问
writer()
{
while(1)
{
wait(rw);
writing;
signal(rw);
}
}
reader()
{
while(1)
{
wait(mutex);
if(count == 0) //若当前没有读者,申请阅读
wait(rw);
count++;
signal(mutex);
reading;
wait(mutex);
count--;
if(count == 0) //若当前没有读者,释放信号量,写者可以进入
signal(rw);
signal(mutex);
}
}
3,打印机问题,问题描述:3个并发进程,共享打印机,只有一个缓冲区,R从输入设备读信息,读出后,放入缓冲区;进程M在缓冲区中加工信息;进程p把加工后的信息,输出;
Semaphore m1 = 0; //是否有未被处理的数据
Semaphore m2 = 0; //是否有被处理的数据
Semaphore empty = 1;
Semaphore mutex = 1;
R()
{
while(1)
{
wait(empty);
wait(mutex);
put data to buffer;
signal(mutex);
signal(m1);
}
}
M()
{
while(1)
{
wait(m1);
wait(mutex);
process the data;
signal(mutex);
signal(m2);
}
}
P()
{
wait(m2);
wait(mutex);
output the data;
wait(mutex);
wait(empty);
}