1.锁
先引进锁这个概率,锁是用来解决临界区互斥访问的一个简单工具。通过进程访问某临界区,需先对其上锁lock,进程结束时释放锁release,在上锁时不允许别的进程访问,在释放完后,后续的进程才可访问。这样的工具称为互斥锁。
但其缺点是忙等待。
2.信号量进制解决同步互斥
信号量是用来记录系统某个资源的数量,如打印机的数量为1,其对应的信号量就为1,可以理解为某储存资源数量的一个变量。
原语是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。
wait、signal原语常简称为P、V操作(来自荷兰语proberen和 verhogen)。因此,做题的时候常把wait(S)、 signal(S)两个操作分别写为P(S)、V(S)。
1.整数型信号量
用一个整数型的信号量来表示系统的某资源的数量。//代码用来示例,并不是这样的
对整数型信号量操作只有三种:初始化,p操作,v操作
int s = 1 //初始化
void wait (s)//表明你要访问资源
{
while(s<=0);
s--;
}
void signal(s)//表示你要释放资源
{
s++;
}
对于某个进程来说,
//进程p0
//....
//wait(s);
//....访问资源
//signal(s);释放
//....
但还是不满足让权等待。
2.记录型信号量
3.用记录型信号量解决同步,互斥
wait即P操作,signal即V操作。
互斥:先设置互斥量mutex=1,在某个需要访问互斥的代码前执行P(mutex),再之后执行V(mutex)。
semaphore mutex = 1;
p1(){
....
P(mutex);
....
V(mutex);
....
}
这样便实现了对某资源的互斥访问。
tips:P、V操作必须成对出现。缺少P(mutex)就不能保证临界资源的互斥访问。缺少V(mutex)会导致资源永不被释放,等待进程永不被唤醒。
同步:
- 设置同步信号量s,初始为0
- 在“前操作”之后执行v(S)
- 在“后操作”之前执行P(S)
下面通过一个例子来解释,要求:进程2的代码4必须在进程1的代码2之后执行。
其实每一对前驱关系都是一个进程同步问题(需要保证一前一后的操作),因此,
1.要为每一对前驱关系各设置一个同步变量
2.在“前操作”之后对相应的同步变量执行V操作
3.在“后操作”之前对相应的同步变量执行Р操作