1.什么是进程同步?
进程同步是一种能让多个进程有秩序的运行的机制,它具体分为:硬件同步机制,信号量机制,管程机制。
2.相关专业术语
(1)间接相互制约关系:几个进程通过共享的资源形成的制约关系。
(2)直接相互制约关系:几个进程为完成同一个任务形成的关系。
(3)临界资源:一次只能供一个进程使用的资源(如打印机),故各进程之间采用互斥的方式实现对这种资源的共享。
(4)临界区:有临界资源知,不论是硬件临界资源还是软件临界资源,各进程必须要互斥的对它进行访问。而人们则把每个进程中访问及临界资源的那段代码称为临界区,所以临界区就是一段代码组成的。
(5)同步机制应遵循的规则:空闲让进,忙则等待,有限等待(对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免进入“死等”),让权等待(当进程不能进入自己的临界区时,应立即释放处理机,以免陷入“忙等”)
3.锁的概念
在对临界区进行管理时,可以将标志一个锁,“锁开”进入,“锁关”等待,初始时锁是打开的。每个要进入临界区的进程必须先对锁进行测试,当锁未开时,则必须等待,直至锁被打开。反之,当锁是打开的时候,则立即把其锁上,以阻止其他进程进入临界区,显然,为防止多个进程同时测试到锁为打开的情况,测试和关锁操作必须是连续的,不允许被分开。
4.硬件同步机制
(1)利用关中断实现互斥:在进入锁测试之前关闭中断,直到完成锁测试并上锁后才能打开中断。
(2)利用Test-and-Set指令实现互斥:
boolean TS(boolean *lock)
{
boolean old;
old = *lock;
*lock = TRUE;
return old;
}
利用TS指令实现互斥的循环进程结构如下
do{
whileTS(&lock);
critical secition;
lock = FALSE;
remainder section;
}while(TRUE)
(3)利用Swap指令(对换指令)实现进程互斥:
void Swap(boolean *a,boolean *b)
{
boolean temp;
temp = *a;
*a = *b;
*b = temp
}
每一个临界资源设置一个全局的布尔变量lock,初值为false,在每个进程中再利用一个局部变量key,利用Swap实现互斥。
循环描述如下:
do{
key = TRUE;
do{
Swap(&lock,&key);
}while(key!=FALSE);
临界区操作;
lock = FALSE;
.....
}while(TRUE)
(4)信号量机制(已被广泛应用)
1)整型信号量:
整形信号量是一个用于表示资源数量的整型量,用S表示,除了初始化外,它只能通过两个标准的原子操作wait(S)和signal(S)【又称P,V操作】来访问,它们的描述如下:
wait(S){
while(S<=0);
S--;
}
signal(S){
S++;
}
当一个进程在修改某信号量时,其他进程不能对该信号量进行修改。
2)记录型信号量
通过整型信号量中的wait(S)中,我们知道只要是信号量S<=0,就会不断测试,因此,该机制没有遵循“让权等待”原则,而让进程陷入“忙等”。所以我们需要改进,因此记录型信号量出现。
记录型信号量是由于采用了记录型的数据结构而得名:
typedef struct{
int value;
struct process_control_block *list;
}semaphore;
value代表资源数目,list是一个进程链表指针,用于链接所有等待进程
相应的,wait(S)和signal(S)操作如下:
wait(semaphore *S){
S->value--;
if(S->value<0)block(S->list);
}
signal(semaphore *S){
S->value++;
if(S->value<=0)wakeup(S->list);
}
上述的进程互斥针对的是多并发进程共享一个临界资源的情况。
3)AND型信号量
在有些情况,一个进程往往需要获得两个或更多的资源后才能执行任务,因此AND型信号量出现。AND同步机制的基本思想是:将进程在运行过程中需要的所有资源,一次性全部分配给进程,待进程使用完后再一起释放,只要有一个资源未能分配给进程,其他所有资源可能为之分配的资源也不会分配给它。由死锁理论可知,这样就可避免上述死锁情况发生。为此在wait操作中增加一个“AND”条件,故称为AND同步,或称为同时wait操作,即Swait(Simultaneous wait)定义如下:
Swait(S1,S2,...,Sn)
{
while(TRUE)
{
if(Si>=1&&...&&Sn>=1){
for(i = 1;i<=n;i++)Si--;
break;
}
else {
place the process in the waiting queue associated with the first Si
found with Si>1,and set the program count of this process to the
beginning of Swait operation
}
}
}
Ssignal(S1,S2,...Sn){
while(TRUE){
for(i = 1;i<=n;i++){
Si++;
Remove all the process waiting in the queue associated with Si
into the ready queue
}
}
}
4)信号量集
在前面所述的记录型信号量机制中,wait(S)或signal(S)操作仅能对信号量进行加1或减1操作,意味着每次只能对某类临界资源进行一个单位的申请或释放,当一次需要N个单位时,便要进行N次wait(S)操作,这显然是低效的,甚至会增加死锁的概率。此外,在有些情况下,为了确保系统的安全,当申请的资源数目低于某一下限时,还必须进行管制,不分配资源。因此,当进程申请某类资源时,在每次分配之前,都必须测试资源的数目,判断是否大于可分配的下限值,决定是否给予分配。基于上述两点,我们可以对AND信号量机制加以扩充,对进程所申请的所有资源以及每类资源不同的资源需求量,在一次P,V原语操作中完成申请或释放。进程对信号量的的测试值是该资源的分配下限值t,即要求S>=t,否则不给分配,一旦允许分配,进程对该资源的需求值为d,表示资源占用量,进行S = S-d的操作,由此形成一般化的信号量集机制,对应的Swait和Ssignal格式为:
Swait(S1,t1,d1,…Sn,tn,dn);
Ssignal(S1,d1,…,Sn,dn);