进程同步和信号量 PV操作
进程同步和PV操作理解
首先用python模拟了生产者消费者问题,代码如下:
import threading import random BUFFER_SIZE = 10 buffer = [[]] * 10 counter = 0 in_ = 0 out_ = 0 item = 0 def productor(): global in_, buffer, counter, item while 1: # 发信号停 while counter == BUFFER_SIZE: print("productor wait... ") item = random.randint(1, 1000) buffer[in_].append(item) print("product {} ".format(item)) print("product counter {} ".format(counter)) in_ = (in_+1) % BUFFER_SIZE # 发信号走 counter += 1 def customer(): global out_, buffer, counter, item while 1: # 发信号停 while counter == 0: print("customer wait... ") item = buffer[out_].pop() print("custom {} ".format(item)) print("custom counter {} ".format(counter)) out_ = (out_+1) % BUFFER_SIZE # 发信号走 counter -= 1 productorThread = threading.Thread(target=productor) customerThread = threading.Thread(target=customer) productorThread.start() customerThread.start() # 信号只能表达有还是没有,而信号量可以表达更丰富的信息
这里面没有用信号量来,是用counter来表示资源,信号量机制我觉得和counter不同的是,
信号量在大于0时,表示资源,在小于0时表示等待的进程
这也就是为什么PV操作要这样写
下面是伪代码,信号量是一种数据结构 semaphore{ 变量 s 表示资源数量 进程 q 表示等待的进程 由阻塞队列表示 } P(semaphore s) s-- 表示资源数 - 1, if s < 0 那么进程等待 V(semaphore s) s++ 表示资源数 + 1 if s <= 0 那么唤醒阻塞队列中的进程
为什么上面是小于0等待,下面是小于等于0唤醒呢?我觉得原因如下;
首先信号量s在大于0时表示资源,小于0时表示等待进程个数
举个例子,以打水为例,可以往一个盆里倒水,但是每次只能从水池接一桶水,然后倒水,不能同时从盆里打水,盆里最终多可以容纳10桶水。
那么这里,最多能倒10桶水就是资源,设empty表示空闲资源即初始值为10(表示当前可倒10桶水,但是现在还没有),full表示盆中已有几桶水初始值为0(其实一些初学者迷惑在这里,为什么要设empty和full两个变量)
所以作为生产者,需要先进行P操作,即P(empty),empty会-1,并判断empty不小于0,那么继续,并且在结尾,需要V(full)操作,打了一桶水,那么盆中多一桶水。
假设empty此时是0,意思也就是说不能在倒水了,那么经过s--,此时empty变成-1,生产进程阻塞了,也就是说多了一个阻塞进程
对于喝水的也就是消费者来说,开始需要判断有没有水,也就是P操作,P(full),此时full为10,那么继续,一样的,结尾需要,V操作,因为喝水的用了一桶水,那么就是说
还可以再打一桶水,所以结尾需要V(empty),将可用资源+1,此时,empty变为0,并且进行V操作,即V(empty)因为V操作中,是小于等于0,所以从阻塞队列中唤醒生产者进程
由于生产者进程之前在P操作时阻塞,所以开始继续执行后面的语句,注意的是,这里是继续,继续,继续执行。
所以PV操作是走走停停的,上述的信号量机制是记录型信号量,不会出现满等情况,也就是满足让权等待
除了记录型信号量,还有整数型信号量,如下:
P(): while s <= 0; s -= 1 v(): s += 1 在整数型信号量中,s 代表资源,记录型中还代表阻塞的进程数, 比如s小于等于0时,此时执行P操作等待,可能会出现忙等情况 即不满足让权等待