操作系统-同步知识详解

背景

引入临界段问题,其解决方案可以保证共享数据的一致性

提出了临界截面问题的软硬件解决方案

引入原子事务的概念,并描述确保原子性的机制

对共享数据的并发访问可能导致数据不一致

维护数据一致性需要确保协作过程有序执行的机制

假设我们希望为填满所有缓冲区的消费者-生产者问题提供一个解决方案。

为此,我们可以使用一个整数计数来跟踪满缓冲区的数量。

最初,count设置为0。生产者在产生一个新的缓冲区后递增,消费者在消耗一个缓冲区后递减。

制作人

while (true) {

      /*  produce an item and put in nextProduced  */
      while (count == BUFFER_SIZE)
		; // do nothing
	       buffer [in] = nextProduced;
	       in = (in + 1) % BUFFER_SIZE;
	       count++;

}

顾客

​ while (true) {
​ while (count == 0)
​ ; // do nothing
​ nextConsumed = buffer[out];
​ out = (out + 1) % BUFFER_SIZE;
​ count–;

​ /* consume the item in nextConsumed
​ }

竞争条件

Count ++可以实现为

register1 =计数

Register1 = Register1 + 1

数= register1

Count—可以被执行为

register2 =计数

Register2 = Register2 - 1

数= register2

将这个执行与“count = 5”交织在一起:

S0: producer execute register1 = count {register1 = 5}

S1:生产者执行register1 = register1 + 1 {register1 = 6}

S2: consumer execute register2 = count {register2 = 5}

S3:用户执行register2 = register2 - 1 {register2 = 4}

S4: producer execute count = register1 {count = 6}

S5: consumer execute count = register2 {count = 4}

关键部分的问题

  • 临界区问题
  • 一个典型的过程Pi的一般结构
  • 临界截面问题的解
  1. 互斥——如果进程Pi在它的临界区执行,那么其他进程就不能在它们的临界区执行

  2. 进程——如果没有进程在其关键区段中执行,并且存在一些进程希望进入它们的关键区段,那么将进入下一个关键区段的进程的选择就不能无限期地推迟

  3. 有限制的等待——在一个进程发出请求进入其临界区之后和该请求被批准之前,其他进程被允许进入其临界区的次数必须存在一个限制

    假设每个进程以非零速度执行

    没有关于N个过程的相对速度的假设

彼得森的解决方案

两个流程解决方案

假设LOAD和STORE指令是原子指令;也就是说,不能被打断。

这两个过程共享两个变量:

int转;

布尔标志[2]

可变转数表示进入临界段的转数。

标志数组用于指示进程是否准备好进入临界区。flag[i] = true表示进程Pi已经准备好了!

  • 过程Pi算法

​ do {
​ flag[i] = TRUE;
​ turn = j;
​ while (flag[j] && turn == j);
​ critical section
​ flag[i] = FALSE;
​ remainder section
​ } while (TRUE);

  • 证明该算法是正确的
  1. 互斥保持不变

2.满足了进度要求。

3.满足有界等待需求

​ do {
​ flag[i] = TRUE;
​ turn = j;
​ while (flag[j] && turn == j);
​ critical section
​ flag[i] = FALSE;
​ remainder section
​ } while (TRUE);

​ do {
​ flag[j] = TRUE;
​ turn = i;
​ while (flag[i] && turn == i);
​ critical section
​ flag[j] = FALSE;
​ remainder section
​ } while (TRUE);

​ do {
​ flag[i] = TRUE;
​ turn = j;
​ while (flag[j] && turn == j);
​ critical section
​ flag[i] = FALSE;
​ remainder section
​ } while (TRUE);

​ do {
​ flag[j] = TRUE;
​ turn = i;
​ while (flag[i] && turn == i);
​ critical section
​ flag[j] = FALSE;
​ remainder section
​ } while (TRUE);

  • 3.满足有界等待需求

​ do {
​ flag[i] = TRUE;
​ turn = j;
​ while (flag[j] && turn == j);
​ critical section
​ flag[i] = FALSE;
​ remainder section
​ } while (TRUE);

​ do {
​ flag[j] = TRUE;
​ turn = i;
​ while (flag[i] && turn == i);
​ critical section
​ flag[j] = FALSE;
​ remainder section
​ } while (TRUE);

同步的硬件

任何解决临界截面问题的方法都需要一个简单的工具——一把锁。

通过要求用锁保护关键区域,可以防止出现竞争条件

​ do {
​ acquire lock
​ critical section
​ release lock
​ remainder section
​ } while (TRUE);

许多系统为关键段代码提供硬件支持

单处理器——可以禁用中断

当前运行的代码将在没有抢占的情况下执行

通常在多处理器系统上效率太低

使用此功能的操作系统不能广泛地扩展

现代机器提供特殊的原子硬件指令

原子= non-interruptable

要么测试记忆字和设定值

或者交换两个记忆词的内容

  • TestAndndSet指令

Definition:
boolean TestAndSet (boolean *target)
{
boolean rv = target; / Test */
target = TRUE; / Set */
return rv:
}

  • 解决方案使用TestAndSet

Shared boolean variable lock., initialized to false.
Solution (Mutual-Exclusion):
do {
while ( TestAndSet (&lock ))
; // do nothing
// critical section
lock = FALSE;
// remainder section
} while (TRUE);

交换指令

​ Definition:

​ void Swap (boolean *a, boolean *b)
​ {
​ boolean temp = *a;
​ *a = *b;
​ *b = temp:
​ }

  • 解决方案使用交换

Shared Boolean variable lock initialized to FALSE; Each process has a local Boolean variable key
Solution(Mutual-Exclusion):
do {
key = TRUE;
while ( key == TRUE)
Swap (&lock, &key );
// critical section
lock = FALSE;
// remainder section
} while (TRUE);

TestandSet()的有界等待互斥

​ do {
​ waiting[i] = TRUE;
​ key = TRUE;
​ while (waiting[i] && key)
​ key = TestAndSet(&lock);
​ waiting[i] = FALSE;
​ // critical section
​ j = (i + 1) % n;
​ while ((j != i) && !waiting[j]) (Find next waiting process)
​ j = (j + 1) % n;
​ if (j == i)
​ lock = FALSE; (No one is waiting)
​ else
​ waiting[j] = FALSE; (process j enters next)
​ // remainder section
​ } while (TRUE);

  • 证明该算法是正确的

\1. 互斥保持不变

\2. 满足了进度要求。

3.满足有界等待需求

信号量

基于硬件的CS问题解决方案对于应用程序程序员来说是复杂的。

为了克服这个困难,我们使用了一种叫做信号量的同步工具。

信号量S -整数变量

修改S的两个标准操作:wait()和signal()

最初称为P()和V()

那么复杂

只能通过两个不可分割(原子)操作访问

wait (S) {
while S <= 0 /* Semaphore S is occupied /
; // no-op
S–; /
Semaphore S is available, get it /
}
signal (S) {
S++; /
Release the semaphore S */
}

信号量使用

计数信号量-在一个不受限制的域上的整数范围

二进制信号量-整数值只能在0到1之间;可以更简单地实现吗

也称为互斥锁,因为它们是提供互斥的锁。

我们可以使用二进制信号量来处理多进程的CS问题。

n个进程共享一个初始化为1的互斥信号量

使用信号量的互斥实现

  • 提供互斥(Process Pi)

Semaphore mutex; // initialized to 1
do {
wait (mutex);
// Critical Section
signal (mutex);
// remainder section
} while (TRUE);

计数信号量可用于控制对由有限数量实例组成的给定资源的访问。

信号量被初始化为可用资源的数量。

要使用资源,请使用wait()

要释放一个资源,使用signal()

信号量可以用来解决各种同步问题。

例如,我们有两个过程P1和P2。先执行S1,再执行S2: sync = 0

信号量实现

以前的互斥解决方案的主要缺点是等待繁忙(CPU浪费)。

这种类型的信号量称为自旋锁。

为了克服这个问题,我们可以使用block和唤醒操作的概念。

Typedef struc {
int value;
struct process *list;
} semaphore

  • 没有繁忙等待的信号量实现

每个信号量都有一个相关的等待队列。等待队列中的每个条目有两个数据项:

值(整数类型)

值> 0表示信号量仍然可用

值= 0表示信号量被占用

没有等待处理

“< 0”表示等待进程数

指向列表中下一条记录的指针/等待列表/

两个操作:

阻塞-将调用该操作的进程放置在适当的等待队列上。

唤醒——删除等待队列中的一个进程,并将其放入就绪队列中。

Implementation of wait

​ wait(semaphore *S) {
​ S.value --;
​ if (S.value < 0) {
​ add this process to S.list;
​ block();
​ }
​ }

实现的信号

​ signal(semaphore *S) {
​ S.value ++;
​ if (S.value <= 0) {
​ remove a process P from S.list;
​ wakeup§;
​ }
​ }

  • 没有繁忙等待的信号量实现

注意,信号量的值可能是负数。

它的大小是等待该信号量的进程数量。

等待进程列表可以通过每个进程控制块(PCB)中的链接字段轻松实现。

  • 死锁和饥饿

死锁——两个或多个进程无限期地等待只由一个等待进程引起的事件

设S和Q是两个初始化为1的信号量

饥饿——无限期的阻塞。一个进程可能永远不会从它被挂起的信号量队列中删除

优先级反转

优先级反转——当低优先级进程持有高优先级进程所需的锁时的调度问题。

三个进程L, M, H,优先级为L < M < H

假设进程H需要资源R,进程l正在使用资源R。进程H等待。

假设进程M变为可运行状态,从而抢占进程L。

间接地,一个较低优先级的进程——M——影响了H必须等待L释放R的时间。

优先级继承协议——所有正在访问高优先级进程所需资源的进程都将继承高优先级进程,直到它们完成资源的使用。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑白极客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值