操作系统概念 6.4章节 硬件同步之采用指令test_and_set()的互斥实现原理解析
1、技术背景
书中原文:
通过加锁的方式来解决临界区的问题,许多现代系统提供特殊的硬件指令,用于检测和修改字的内容,或者用于原子地交换两个字(作为不可中断地指令)。我们可以采用这些特殊的指令,相对简单地解决临界区问题,在这里通过指令test_and_set()
和compare_and_swap()
抽象了这些指令背后地主要概念。
2、问题分析
2.1 指令test_and_set()
可以按照如下代码来定义:
这一指令的重要特征是:它的执行时原子的。
bool test_and_set(bool *target)
{
bool rv = *target;
// 通过地址寻址,真实地修改target的值
*target = true;
// 返回的是传入时target的值
return rv;
}
代码分析:
该函数通过指针传入参数target
,在函数体中创建了临时变量rv
来存储target
的初始值,然后真实地修改target
所指向内存地址的值为true
,并将临时变量rv
的值返回。
场景举例:
- case1:传入参数为
false
,那么该函数会返回false
,但过程中会真实地修改target
所指向内存地址的值为true
。 - case2:传入参数为
true
,那么该函数会返回true
,此时过程中对target
所指向内存地址的修改操作将不会引起变化。
2.2 采用指令test_and_set()
的互斥实现原理解析
如果一台机器支持指令test_and_set()
,那么可以这样实现互斥,声明一个布尔变量lock
,初始化为false
。进程P
的结构如下代码:
/**
* 采用指令test_and_set()的互斥实现
*/
do {
// 进入区代码
while(test_and_set(&lock));
// 临界区资源操作
criricalSectionOperation();
// 退出区代码
lock = false;
// 剩余区
doSomethingElse();
} while (true);
代码分析:
从代码中可以看到共分为四块,分别是进入区、临界区、退出区和剩余区。其中进入区的while(test_and_set(&lock));
语句中的lock
便是我们声明的变量,它就代表着临界区资源锁的状态。
场景举例:
假设当前为false
,则说明当前临界区资源没有上锁。此时某进程P1
想要进入临界区,由于进入区的while
循环条件test_and_set(&lock)
为假,当前进程可以进入临界区执行相应的操作(注意此时lock
变量的值已经被test_and_set()指令修改为true
),在执行完临界区操作完毕后会执行到退出区的lock = false;
语句,该语句代表着对临界区资源锁的释放。
接下来解释如何如何实现的互斥。
我们假设当前状态时进程P1
还在执行临界区操作,而此时有另外一个进程P2
也想要进入临界区,那么它也会执行相同的代码块------执行到进入区代码while(test_and_set(&lock));
。由于进程P1
还没有执行完临界区操作,那么它不会对临界区资源的锁进行释放,即当前变量lock
的值为true
,所以P2
进程会在进入区的while()
循环代码无限循环,从而实现了进程P1
和进程P2
互斥的访问临界区资源。
3、心得
由于是菜鸡自学,所以连简单的代码都需要仔细地分析才能明白其中的原理,一开始眼高手低了,看着就这么简单的几行代码看看就会了,后来分析着就感觉没那么简单,还是要踏踏实实地去举例分析才能理解的比较透彻啊!