进程同步、互斥的软、硬件实现原理

进程同步、互斥

进程同步

  • 进程具有异步性的特征。异步性是指各并发执行的进程以各自独立的、不可预知的速度向前推进。

  • 同步也叫做直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调他们的工作次序而产生的制约关系。进程间的直接制约关系>就是源于它们之间的相互合作。

进程互斥

进程的 “ 并发 ” 需要 “ 共享 ” 的支持。各个并发执行的进程不可避免的需要共享一些系统资源(比如内存,打印机、摄像头这样的 I/O设备)。

资源共享方式

  • 互斥共享方式 :系统中的某些资源,虽然可以提供给多个进程使用,但一个时间段内只允许一个进程访问该资源
  • 同时共享方式 : 系统中的某些资源,允许一个时间段内由多个进程 “同时” 对他们进行访问

互斥

我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(比如摄像头、打印机)都属于临界资源。此外还有很多变量、数据、内存缓冲区等都属于临界资源。

对临界资源的访问,必须互斥的进行。互斥,也叫做间接制约关系。进程互斥指当一个进程访问某临界资源时,另一个想要访问该资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源

实现临界资源互斥访问的四大原则

  1. 空闲让进。临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区;
  2. 忙则等待。当已有进程进入临界区时,其他试图进入临界区的进程必须等待;
  3. 有限等待。对请求访问的进程,应保证能在有限时间内进入临界区(保证不会饥饿);
  4. 让权等待。当进程不能进入临界区时,应立即释放处理机,防止进程忙等待。
do{
	entry section; // 进入区
    critical section; // 临界区
    exit section; // 退出区
    remainder section; // 剩余区
}while(1)

进程互斥的软件实现方法(可以理解为用代码实现)

单标志法

在进入区只做 “检查”,不 “上锁”

在退出区把临界区的使用权转交给另一个进程(相当于在退出区既给另一进程 “解锁”,又给自己 “上锁”)

主要问题:不遵守 “空闲让进”原则

算法思想:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予

int turn = 0; // turn 表示当前允许进入临界区的进程号
// P0进程
while (turn != 0); // 进入区
critical section; // 临界区
turn = 1; // 退出区
remainder section; // 剩余区

// P1进程
while (turn != 1); // 进入区
critical section; // 临界区
turn = 0; // 退出区
remainder section; // 剩余区

为什么说单标志检查法违背 “空闲让进”原则?

​ 当P0进程执行完进入区之后,并没有访问临界区时,P1进程也只能在执行进入区的时候一直等待,而临界区始终没有进程进入。


双标志先检查法

在进入区先 “检查” 后 “上锁”,退出区 “解锁”

算法思想:设置一个布尔型数组flag[],数组中各个元素用来标记各进程想进入临界区的意愿,比如 “flag[0] = true” 表示 0号进程 P0现在想要进入临界区。每个进程在进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应的标志 flag[i]设为true,之后开始访问临界区。

bool flag[2]; // 表示进入临界区
flag[0] = false;
flag[1] = false; // 刚开始两个进程都不想进入临界区

// P0进程
while (flag[1]); // 如果此时 P1想进入临界区,P0就一直循环等待
flag[0] = true; // 标记为 P0进程想要进入临界区
critical section; // 访问临界区
flag[0] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

// P1进程
while (flag[0]); // 如果此时 P0想进入临界区,P1就一直循环等待
flag[1] = true; // 标记为 P1进程想要进入临界区
critical section; // 访问临界区
flag[1] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

为什么说双标志先检查法违背 “忙则等待”原则?

​ 如果按照步骤 6、13、7、14…的顺序执行,P0和P1将会同时访问临界区。(进程的异步性,进程之间是并发执行的)

原因:由于进入区的 “检查” 和 “上锁” 两个处理不是一气呵成的。“检查” 后,“上锁” 前可能发生进程切换。


双标志后检查法

在进入区先 “加锁” 后 “检查”, 退出区 “解锁”

算法思想:双标志先检查法的改版。前一个算法的问题是先 “检查” 后 “上锁”,但是这两个操作又无法一气呵成,因此导致了两个进程同时进入临界区的问题。因此,人们又想到先 “上锁” 后 “检查”的方法,来避免上诉问题。

bool flag[2]; // 表示进入临界区
flag[0] = false;
flag[1] = false; // 刚开始两个进程都不想进入临界区

// P0进程
flag[0] = true; // 标记为 P0进程想要进入临界区
while (flag[1]); // 如果此时 P1想进入临界区,P0就一直循环等待
critical section; // 访问临界区
flag[0] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

// P1进程
flag[1] = true; // 标记为 P1进程想要进入临界区
while (flag[0]); // 如果此时 P0想进入临界区,P1就一直循环等待
critical section; // 访问临界区
flag[1] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

为什么说双标志后检查法违背 “空闲让进” 和 “有限等待” 原则?

​ 如果按照先 6后 13的步骤,当两个进程都执行到进入区时,两个进程都一直等待。

双标志后检查法虽然解决了 “忙则等待”的问题,但是又出现了 空闲让进和有限等待的问题,会使得各进程都无法访问临界资源而产生饥饿现象


Peterson算法

在进入区 “主动争取–主动谦让-检查对方是否想进,己方是否谦让”

主要问题:不遵循 “让权等待”原则,会发生 “忙等”

算法思想:双标志后检查法中,两个进程都争着进入临界区,但是谁都不让谁,最后谁都无法进入临界区。Peterson算法的思想是,可以让进程尝试 “互相谦让”,主动让对方先试用临界区。

bool flag[2]; // 表示进入临界区意愿的数组,初始都为 false
int turn = 0; // turn 表示优先让哪个进程进入临界区

// P0进程
flag[0] = true; // 标记为 P0进程想要进入临界区
turn = 1; // 主动让出访问权限
while (flag[1] && turn == 1); // 如果此时 P1想进入临界区且 P0进程作出了让步设置 turn为 1,P0就一直循环等待
critical section; // 访问临界区
flag[0] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

// P1进程
flag[1] = true; // 标记为 P1进程想要进入临界区
turn = 0;
while (flag[0] && turn == 0); // 如果此时 P0想进入临界区,P1就一直循环等待
critical section; // 访问临界区
flag[1] = false; // 访问完临界区,修改标记为 P1不想使用临界区
remainder section;

为什么说Peterson算法违背 “让权等待” 原则?

​ 由于Peterson算法必会使得一个进程进入临界区,但是没有进入临界区的进程在等进入临界区的进程释放临界区,期间一直在询问临界区是否空闲,且一直会占用处理机时间片。

:Peterson算法用软件方法解决了进程互斥问题,遵循了空闲让进、忙则等待、有限等待三个原则,但是依然未遵循让权等待的原则。

Peterson算法相较于之前三种软件解决方案来说,是最好的,但是依然会存在问题。


进程互斥的硬件实现方法(可以理解是操作系统自带的,直接操作硬件)

中断屏蔽方法

使用 “开/关中断”指令实现

优点:简单高效

缺点:只适用于单处理机;只适用于操作系统内核进程(开/关中断运行在核心态)

利用 “开/关中断指令”实现(与源于的实现思想相同,即在某进程开始访问临界区到结束访问为止都不允许被中断,也就不能发生进程切换,因此也不可能发生两个同时访问临界区的情况)

...
关中断; // 关中断后即不允许当前进程被中断,也必然不会发生进程切换
临界区;
开中断; // 直到当前进程访问完临界区,再执行开中断指令,才有可能有别的进程上处理机并访问临界区
...

缺点:不适用于多处理机;只适用于操作系统内核进程,不适用于用户进程(开/关中断指令只能运行在内核态,这组指令如果能让用户随意使用会很危险)


TestAndSet(TS指令/TSL指令)

old 记录是否已被上锁;

再将 lock 设为 true;

检查临界区是否已被上锁(若已上锁,则循环重复前几步)

优点:实现简单;适用于多处理机环境;

缺点:不满足 “让权等待” 原则

简称 TS 指令,也可称为 TestAndSetLock 指令,或 TSL 指令

TSL 指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成

以下代码只是用来理解实现的步骤,并不是 TS 指令,TS指令直接用硬件实现

// 布尔型共享变量 lock 表示当前临界区是否被加锁
// true 表示已加锁,false 表示未加锁
bool TestAndSet (bool* lock){
    bool old;
    old = *lock; // old 用来存放lock原来的值
    *lock = true; // 无论之前是否已加锁,都将 lock设为 true
    return old; // 返回 lock原来的值
}

// 以下是使用 TSL 指令实现互斥的算法逻辑
while (TestAndSet (&lock)); // “上锁” 并“检查”
临界区代码段...
lock = false; // 解锁
剩余区代码段...

Swap指令(Exchange指令 / XCHG指令)

Swap指令是用硬件实现的,执行的过程不允许被中断,只能一气呵成。

优缺点同 TSL指令

主要逻辑用C++来描述帮助理解

// Swap 指令的作用是交换两个变量的值
void Swap (bool* a, bool* b){
    bool temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

// 以下是用 Swap指令实现互斥的算法逻辑
// lock 表示当前临界区是否被加锁
bool old = true;
while (old == true)
    Swap(&lock, &lock);
临界区代码段...
lock = flase; // 解锁
剩余区代码段...

优点:实现简单,无需像软件实现方法那样严格检查是否会有逻辑漏洞;适用于多处理机环境;

缺点:不满足 “让权等待” 原则,暂时无法进入临界区的进程会占用CPU并循环执行TSL指令,从而导致忙等且一直占用处理机资源。


补充

并发和并行的区别

并发:逻辑上很多个任务可以同时进行,但是物理上是多个任务互相切换以达到同时进行的效果

并行:在实际运行上是做到了多个任务同时进行

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值