ts 变量后面加问号或者叹号_关于记录型信号量与TS指令的理解

在实现多线程互斥访问共享变量中,除了使用互斥锁之外,还可以使用信号量,当然信号量不仅仅能够实现互斥,还能够实现同步问题。

信号量的历史这里就不写了,信号量的分类也有几种,这里仅仅讨论一下记录型信号量。

记录型信号量是一个与队列有关的整型变量,大白话来讲,记录型信号量是一种数据结构,除了一个整型变量外,还有一个队列,记录型信号量定义如下:

type semaphore=record
    value:integer; # 整形变量
    Q: list of process;  # 队列
    end

记录型信号量仅仅能够被P原语和V原语进行操作,P原语申请资源,V原语释放资源,那P原语和V原语是如何实现原子性操作的?

在深入探索P原语和V原语之前,我们知道了可以利用Test and Set指令(swap指令)实现互斥锁的acquire方法(点这里):

# Test and Set(python),原子性操作
def TS(lock):
    if lock == 0:
        lock = 1
        return True
    return False
# 利用TS指令实现acquire方法 
def acquire():
    while not TS(lock):
        pass // 忙等状态

可以看到,在锁处于open状态时,TS指令保证了只能有一个线程能够改变锁的状态,使锁处于locked状态,在由locked改变为open状态之前,其他来获取锁的线程只能while循环,不能够获得锁。

接下来我们看一看记录型信号量P原语与V原语的伪代码:

# 定义记录型信号量
​
type semaphore=record
    value:integer; # 整形变量
    T: list of thread;   # 队列
    end
    
# P原语
P(s):
    s.value = s.value - 1 # 
    if s.value < 0
        then begin
        block t;
        insert t into T
    end;
​
# V原语
V(s):
    s.value = s.value + 1
    if s.value <= 0
        then begin
            wakeup the first T;
            remove the P from T
    end
​

为了能够更直观的理解P操作和V操作的实现逻辑,可以将上述代码转换为下述流程图:

ed25cefdbfa53b5ecbed9306ecb41971.png

由上述流程图,我们可以看到

信号量的P原语,需要完成两件事:

  1. 当访问value时,将value减1
  2. 当资源被消耗完时,需要将请求资源的当前线程推入阻塞队列

信号量的V原语,需要完成两件事:

  1. 当访问value时,需要将value加1
  2. 当阻塞队列中有阻塞线程时,需要唤醒一个线程

接下来就是重点了,如何利用操作系统的TS指令实现信号量P原语、V原语,使这两个原语具有原子性?

我们可以看到,在使用信号量的时候,value作为共享资源,那就会出现如下几种争抢临界资源的情况:

  • 多个线程的P原语之间
  • 多个线程之间的P、V原语
  • 多个线程之间的V原语

所以在P、V原语内要有互斥控制,保护临界资源不被同时访问到,避免数据不一致的情况,这里需要一个变量来保护临界资源。定义一个mutex,用来保护value,因为有一把互斥锁,获取时都可能会产生忙等现象,除了上述提到的队列T,应该还有一个队列M。

所以现在信号量的内部结构变为:

type semaphore=record
    value:integer
    T:list of Thread wait for value
    M:list of Thread wait for internal mutex
    mutex:boolean = 0 # 互斥锁

P原语:

def acquire():
    while not TS(lock): # 获取mutex,用来互斥访问s.value
        block t
        insert t into M
    s.value = s.value - 1
    if s.value < 0: # 表示资源已经用完了
        lock = 0 # 释放互斥锁,其他的线程或者acquire方法或者release方法可以来访问value了
        wakup the first t from M # 唤醒M队列中的线程
        remove the t from M
        block t         
        insert t into T
    else:
        lock = 0
        wakeup the first t from M
        remove the t from M
            

V原语:

def release():
    while not TS(lock):
        block t 
        insert t into M
    s.value = s.value + 1
    
    if s.value <= 0: # 表明阻塞队列中还有待唤醒的线程
        wakeup the first t from T 
        remove t from T
        
    lock = 0 # 释放锁
    wakeup the first t from M
    remove the t from M

以上就是个人对记录型信号量的理解,以及尝试结合系统的TS指令实现了一下信号量的P原语与V原语,如果您看到了,有理解的不对的地方,欢迎指正,也欢迎与各位进行交流。

参考:

  1. http://faculty.salina.k-state.edu/tim/ossg/IPC_sync/ts.html#implementing-semaphores-with-test-and-set
  2. 图书/计算机操作系统原理与设计
  3. https://www.icourse163.org/course/UESTC-1205790811
  4. https://zhuanlan.zhihu.com/p/136173505
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值