自学内容网 自学内容网

操作系统Lesson8 - 同步互斥机制和编程方法


忙等互斥与睡眠唤醒

为了解决多个进程之间的操作不会相互干扰,于是有了这两种操作。

  • 忙等互斥:小时间事件适用
  • 睡眠与唤醒:长时间事件适用

阻塞:睡眠
忙等:自旋锁
内核中有些适合忙等,因为睡眠需要维护睡眠队列等结构,耗时长,有时不如忙等。

在这里插入图片描述


如何解决

在这里插入图片描述
禁止多个进程同一时刻对共享资源进行读写

  • 共享资源包括:共享内存、共享文件等

进程0-3G独立资源,3~4G共享内核,而文件资源等都是共享的

设立临界区

临界区:将一块共享资源框起来,这段代码就叫临界区。

确保一个或多个进程不会在同一时间对同一共享资源(包括但不限于共享内存、共享文件等)进行读写操作。这要求实现一种称为 互斥(Mutual Exclusion) 的机制,即当一个进程正在使用某共享资源时,其他进程必须被阻止访问该资源。

为了正确高效操作临界区资源,对临界区的锁操作需要遵循以下四个原则:空闲让进、忙则等待、有限等待、让权等待


忙等互斥

为了解决互斥问题,下面列出了多种方法。

屏蔽中断

我直接把其他任务对CPU的打屏蔽了不就行了,就可以独占CPU了。

中断分为两种:
外部IO中断、时钟中断

长期屏蔽中断,CPU无法接收IO消息,也无法被时间片打断,也就无法被其他任务调度,如果此时发生错误,CPU也接收不到中断,会导致死机。

执行方法:程序一进入临界区就屏蔽中断,完成后恢复


可行性

进程进入临界区由谁决定?

  • 如果是用户进程,程序员可决定,那黑客程序怎么办?
  • 所以一般不会给用户,内核来做

对单核处理系统上,最简单

由于多核CPU执行屏蔽中断代码,只是针对自己一个CPU,而其它CPU不知道,所以使用TSL、XCHG指令,用来把整条数据线掐断。

所以说屏蔽中断一般很短



锁变量

锁分两种:自旋锁和互斥锁
自旋锁

  • 忙等锁,不放弃CPU,轮询CPU,不断查询。
  • 适合小周期

互斥锁

  • 阻塞行为,一旦发现资源不可用,睡眠,放弃CPU,等待被另外的程序 段唤醒
  • 适合大周期

在这里插入图片描述

如果用int数据类型定义自旋锁:

  • 我们由上节课可知,从内存取变量分为三步:取出,操作,写回
  • 如果在判断成功后准备将锁置为1时时间片到了,那么锁还是0,被另一个进程抢到然后进入资源区,两个人进入同一资源区,就会造成严重后果。

所以说用软件基本对此(互斥)无能为力。
于是提出了原子变量执行期间无法打断,要么不开始,要么做完。

在这里插入图片描述

由于早期硬件跟不上,于是还是借助软件,实现了:自旋锁
提供接口:
spin_lock();关中断,写入、读取数据
spin_unlock();开中断
在这里插入图片描述

现在:有专门的指令集来(TSL)对此操作,特性:测试设置、比较交换。
而对于之前的接口,软间实现不变,OS根据硬件是否支持硬件中断来决定是否翻译为TSL指令集。


严格轮询法

单变量轮询:

  • 用进程号turn来规定谁能进入临界区;
  • 弊端:
    • 进程0的非临界任务很长,当进程1完成临界任务后将变量设为进程0的进程号后,很快执行完了非临界的任务,
    • 然而变量还是进程0的进程号,进程1没办法访问临界区资源了,违背了空闲让进原则
      在这里插入图片描述

在这里插入图片描述


Peterson算法

有两种:谦让型、主动自信型

问题代码:两个人互相谦让,造成死锁。

在这里插入图片描述
enter函数中:

  • 进程0先抢到时间片执行,将自己状态更新为感兴趣,此时时间片结束;
  • 进程1也之开始执行这个代码段,也将自己的状态更新为感兴趣;
  • 造成死锁,两人互相谦让。

解决方案

在这里插入图片描述

引入turn,等待条件改变:检查对方是否想使用,且谦让轮到他

  • 首先将自己的状态改为感兴趣;
  • 然后尝试谦让给另一个进程:
    • 如果对方进程不感兴趣,我直接就能进入临界区访问资源;
    • 如果对方也感兴趣,就会检查谦让的这个turn轮到谁了,轮到谁,谁能访问,另一个轮询阻塞。

但是未遵循让权等待原则,因为当初设计的时候也没想到这方面。

主动自信型:谁先举手谁先发言。

// 记录当前“轮到”哪个进程进入临界区
int turn;
// 记录每个进程是否有意愿进入临界区
int interested[N];
// 进程号为0或1的进程进入临界区的函数
void enter_region(int process) {
int other = 1 - process; // 计算另一个进程的编号
// 标记本进程希望进入临界区
interested[process] = TRUE;
turn = process; // 尝试将turn设置为当前进程号
// 等待条件:如果turn仍然指向当前进程且另一个进程仍有意愿进入
while (turn == process && interested[other] == TRUE) {
// 忙等待,直到条件不满足
}
}
// 进程离开临界区的函数
void leave_region(int process) {
// 标记本进程已离开临界区
interested[process] = FALSE;
}

TSL指令

从硬件方面锁定,会将总线锁定,其他所有CPU都无法访问,来解决多核问题.
在这里插入图片描述

释放锁无需原子操作

XCHG也是类似的指令,都是将之前的状态读出来并测试。
由于硬件指令提供,一个周期就做完了,能实现多CPU操作


原文地址:https://blog.csdn.net/2301_78981471/article/details/144316402

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!