1.两个或两个以上的进程不能同时使用的资源称为临界资源(Critical Resource,CR)。
临界资源可能是一些独占设备,如打印机、磁带机等;也可能是一些共享变量、表格、链表等。
2.每个进程访问临界资源的那段代码称为临界区(Critical Section)。
必须在临界区前面增加一段用于进行检查的代码,成为进入区;
在临界区后面加一段检查推出临界区的代码,成为退出区,
进程中除去上述进入区和退出区外,其他部分的代码成为剩余区。
do
{
进入区;
临界区;
退出区;
剩余区;
}while(true);
3.进程同步是指有协作关系的进程不断地调整它们之间的相对速度或执行过程,以保证临界资源的合理利用和进程的顺利执行。进程同步机制一般都借助一个中间媒体来实现,如信号量操作、加锁操作等。
4.同步机制应遵循的规则
(1)空闲让进
(2)忙则等待
(3)有限等待(避免“死等”)
(4)让权等待(释放处理机)
5.锁机制
实现互斥的一种软件方法是采用锁机制,即提供一对上锁(Lock)和开锁(UnLock)原语,以及一个锁变量w或者是锁位(1个bit)。w=1,表示上锁;w=0,表示开锁。
//加锁原语
Lock w()
{
while(w==1)
{
保护当前进程的CPU现场;
将当前进程放入w的等待队列,将该进程置为“等待”状态;
转进程调度;
}
}
//开锁原语
UnLock()
{
if(w等待队列不空)
{
移除等待队列首元素;
将该进程置为就绪状态,并放入就绪队列;
}
w=0;
}
6.信号量机制
1965年,荷兰的Dijkstra提出了一种同步机制,它是广义锁机制或称为技术锁,既能解决互斥,又能解决同步。
后发展为信号量集同步机制。
申请和释放临界资源的两个原语操作为wait操作和signal操作,wait(S)和signal(S)有时也称为P原语操作和V原语操作,P和V分别是荷兰语Passeren和Verhoog的第一个字母,相当于Pass和Increment。
信号量(Semaphore)也叫做信号灯,是实现进程的同步与互斥的有效数据结构。我们可以为每类资源设置一个信号量。信号量有多种类型的数据结构,如整型信号量、记录型信号量、AND型信号量及信号量集等。
(1)整型信号量
其数值表示当前系统中可用的该类临界资源的数量。
wait(s):
while(s<=0)
该进程等待;
s=s-1;
signal(s):
s=s+1;;
(2)记录型信号量
struct semaphore
{
int value;
struct PCB* queue;
}semaphore;
信号灯变量说明如下:semaphore S;
S的值表示可用的该类临界资源的数量,而queue为进程链表指针,指向等待该类资源的PCB队列。
//申请临界资源的原语
void wait(S)
{
S.value=S.value-1;
if(S.value>=0)
本进程继续;
else
{
将本进程放入阻塞态队列;//调用block原语,遵循“让权等待”
转进程调度;
}
}
//释放临界资源的原语
void signal(S)
{
S.value=S.value+1;
if(S<=0)
唤醒指针queue所指的阻塞态进程;//调用wakeup原语
}
S.value的绝对值表示在该信号量链表中已阻塞进程的数目。
原语在执行时是不可中断的。
7.飞机订票系统的两个终端T1和T2的并发执行
int n=100;
Semaphore S=1;
//进程:
T1()
{
wait(S);
read(n);
if(n>=1)
{
n=n-1;
write(n);
signal(S);
买一张票;
}
}
//进程:
T2()
{
wait(S);
read(n);
if(n>=1)
{
n=n-1;
write(n);
signal(S);
买一张票;
}
}