- 在临界区共同修改信号量产生错误
第一次执行:
p1.register=empty; p1.register=p1.register-1; empty=p1.register; p2.register=empty; p2.register=p2.register-1; empty=p2.register;z 第二次执行可能由于多个进程并发,调度引发共享数据错误. p1.register=empty; p1.register=p1.register-1; p2.register=empty; p2.register=p2.register-1; empty=p1.register; empty=p2.register;
此处的regist是寄存器,empty是代表可用空闲资源,为2时表示进程有两个资源可用,为-1时表示有一个进程睡眠,处在阻塞队列中。
注意这里不能对empty直接操作,直接用empty操作,在硬件层面数据的的操作也会落实回寄存器中去
- 在写共享变量empty时,采用上锁的方式阻止其他进程野访问empty
临界区(一次只允许一个进程进入执行的一段代码0)
基本原则,互斥进入,有空让进,有限等待.
- 轮滑法
while(turn!=0);进入死循环无限等待 while(turn!=1);
临界区 临界区
turn=1; turn=0;
剩余区 剩余区
<-- 但是不满足有空让进,完成后不能再次进入-->
4.标记法
flag[0]=true flag[1]=false;
while(flag[1]); while(flag[0]=true);
临界区 临界区
flag[0]=false; flag[1]=false;
问题是在执行第一条语句时,切换到另一个线程,双方都会陷入无限等待
5.peterson算法
采用非对称标记和值日法来避免进程切换时造成当前进程无限等待
flag[0]=true flag[1]=false;
turn=1; turn=0;
while(flag[1]&&turn0); while(flag[0]=true&&turn0);
临界区 临界区
flag[0]=false; flag[1]=false;
此算法三条原则全部满足,但是面对多进程会比较麻烦
6.面包店算法
每个进程获取数组中更大的序号,最小序号先执行,离开时序号置为0,
choosing=true;nums[i]=max(nums[0],nums[1],nums[n-1])+1;
choosing=false;
for(int j=0;j<n;j++){
while(choosing);while((nums[i]>nums[j])&&nums[i]!=0);
nums[i]=0;
<--choosing是为了再选取序列号时,其他进程要进入死循环等待
7.关闭中断
另一个进程只有在被调度时才能执行临界区代码,所以通过关闭时钟中断,阻止时间片减小,让进程不被切换.
cli();
临界区
sti();
但是面对多cpu多核情况时,需要同步所有cpu
8.硬件原子指令保护法
{ boolean rv=x;
x=true;
return x;
}
while(x);
临界区
x=false;
锁(信号量)的依赖会来源于硬件,是原子指令,保证数据的一致性。
此时这个函数的代码段对于cpu只是一条机器指令.
** 在多cpu情况下,要锁住总线,**
posted @
2023-02-12 15:23
初冬又十三
阅读(
35)
评论()
收藏
举报