进程的组成
进程由以下内容组成:
PCB:进程控制块,是进程的唯一标识
程序,数据区,工作区
进程的三态
运行态,就绪态,阻塞态
进程之间的互斥
多个进程因争用临界资源而互斥执行,叫做进程间的互斥。实现进程互斥的方法有以下几种:
- Dekker算法:这种算法需要设置一个整型变量turn,用来指示允许进入临界区的线程,turn=1表示P1可以进入临界区,turn=2表示P2可以进入临界区。还要设置一个flag[2]数组表示自己是否愿意进入临界区。flag[0]=true表示进程P1愿意进入临界区,为false表示不愿意进入临界区,flag[1]与P2对应。Dekker算法采用竞争的方式来进入临界区,假如P1想进入临界区,它将自己的flag[0]=true,然后看P2是否愿意进入临界区,如果P2不愿意,那么P1直接进入临界区。如果P2也愿意进入临界区,那么查看turn的值,看当前轮到谁进入临界区了。如果轮到P2进入临界区了,那么P1则表示自己不愿意进入临界区(flag[0]=flase)。将进入临界区权限让给P2.然后一直等P2从临界区退出。
示例代码
void P0()
{
while(true)
{
flag[0] = true;//P0想使用关键区。
while(flag[1])//检查P1是不是也想用?
{
if(turn == 1)//如果P1想用,则查看P1是否具有访问权限?
{
flag[0] = false;//如果有,则P0放弃。
while(turn == 1);//检查turn是否属于P1。
flag[0] = true;//P0想使用。
}
}
visit(0); //访问Critical Partition。
turn = 1; //访问完成,将权限给P1。
flag[0] = false;//P0结束使用。
}
}
void P1()
{
while(true)
{
flag[1] = true; //P1想使用关键区。
while(flag[0]) //检查P0是不是也想用?
{
if(turn == 0) //如果P0想用,则查看P0是否具有访问权限?
{
flag[1] = false; //如果有,则P1放弃。
while(turn == 0); //检查turn是否属于P1。
flag[1] = true; // P1想使用。
}
}
visit(1); //访问Critical Partition。
turn = 0; //访问完成,将权限给P0。
flag[1] = false; //P1结束使用。
}
}
- Peterson算法:这种算法与Dekker算法很相似,但是采用谦让的态度。turn和flag[2]都少不了,而且其含义与Dekker算法一样。先表示自己愿意进入临界区,然后将进入临界区的权限让给对方。
示例代码
void procedure0()
{
while(true)
{
flag[0] = true;
turn = 1; //将进入临界区权限让给对方
while(flag[1] && turn == 1)
{
sleep(1);
printf("procedure0 is waiting!
");
}
//进入临界区
flag[0] = false;
}
}
void procedure1()
{
while(true)
{
flag[1] = true;
turn = 0;
while(flag[0] && turn == 0)
{
sleep(1);
printf("procedure1 is waiting!
");
}
//进入临界区
flag[1] = false;
}
}
这两种算法都会出现忙等待现象,造成资源的浪费。
硬件方法:“开关中断”指令,“交换”指令,“测试与设置”指令,这三种需要CPU指令集的支持,来达到互斥的目的。
进程的同步
进程之间的同步一般使用信号量来实现,P操作获取资源,V操作释放资源。下面是生产者--消费者模型。P1和P2共享缓冲区,S1和S2的初值为1和0。缓冲区满则不能放物品,缓冲区空不能拿物品。缓冲区只能放一件物品。
P1进程
while(true) {
生产一件产品;
P(S1); /*申请空缓冲区*/
放入物品;
V(S2);
}
P2进程
while(true) {
P(S2); /*申请满缓冲区*/
获取物品;
V(S1);
}
P操作会消耗资源,V操作会释放资源。S>0时表示同类资源可用数量,S=0表示无可用资源,S<0时,S的绝对值表示正在被阻塞的进程数量。
进程与线程
进程是资源分配的单位,线程是调用的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(寄存器,栈,程序计数器),它与同一个进程的其他线程共享进程所拥有的全部资源。线程的切换相比于进程来说开销更小(切换时换入换出的内容比进程要小的多,所以速度快)。
死锁产生的必要条件
- 互斥资源的使用(资源独占):自己占有了资源,其它进程就无法共享使用
- 不可剥夺:自己占有的资源不能被剥夺,直到主动释放为之
- 零散请求:不能一次性将所有资源拿到手
- 循环等待:等待资源的进程形成一个环
只要破坏上面的一个条件就不会发生死锁。这是从预防的角度出发,即对资源的申请加以严格的限制,从而不会发生死锁。
死锁的避免
死锁的避免是在进程申请资源之前,看预判一下,满足进程的要求后会不会发生死锁。如果会发生则不分配,如果不发生则分配资源。
单银行家算法
在某一时刻,系统的某种资源(这里是资金)剩余4,这时有四个进程都要申请这种资源,则应将资源分给a或b让其执行。a或b执行后会释放自己占有的资源,这样其它进程可以继续执行了。
多银行家算法
单银行家算法是对单个资源的分发控制,而多银行家算法则控制多个资源。
图a中表示每个进程总共要申请的资源数,图b表示每个进程已经申请到的资源,图c表示每个进程还需要申请的资源。然后给出分配策略。