多线程同步原语(2)——信号量
锁比较简单,通常如之前锁的例子那样,针对一个全局变量的修改。
当情况更加复杂的时候,比如说,控制一批有限资源的时候,使用信号量会是更好的选择
信号量级一个计数器,当消耗资源的时候,计数减少,当释放资源的时候,计数器增加,因为整体的资源是有限的,所以说,当信号量为最大值的时候,就不能在增加,同时当信号量为最小值的时候,也不能在减少了
这方面我也没想到什么好例子,就用参考书(python核心编程)上的糖果机例子吧。
下面模拟一个简化的糖果机,只有5个可以使用的槽来保存糖果,如果所有槽都满了,就不能往机器中加糖果了。如果所有槽都空了,消费者就无法购买糖果了,就有点像一个固定大小的队列,不同的一点是没有顺序的说法。
python中信号量的使用方法,也类似于锁,用了相同的命名,获取资源acquire,释放资源release
from atexit import register
from random import randrange
from threading import BoundedSemaphore,Lock,Thread
from time import sleep,ctime
lock = Lock()
MAX=5
candytray = BoundedSemaphore(MAX)
# 往糖果盘里装糖果的方法
def refill():
# 对信号量进行+1涉及读写操作,需要上锁
lock.acquire()
print('Refilling candy...')
try:
# release 对应信号量的释放资源操作,即+1
candytray.release()
# 若糖果罐满了,会产生ValueError异常
except ValueError:
print('full skipping')
else:
print('OK')
lock.release()
def buy():
lock.acquire()
print('Buying candy...')
# 获取资源也就是糖果
if candytray.acquire(False):
print('OK')
else:
print('empty',skipping)
lock.release()
def producer(loops):
for i in range(loops):
refill()
sleep(randrange(3))
def consumer(loops):
for i in range(loops):
buy()
sleep(randrange(3))
def main():
print('starting at:',ctime())
nloops = randrange(2,6)
print('THE CANDY MACHINE (full with %d bars)!'%MAX)
Thread(target=consumer,args=(randrange(nloops,nloops+MAX+2),)).start()
Thread(target=producer,args=(nloops,)).start()
@register
def _atexit():
print('all Done at:',ctime())
if __name__=='__main__':
main()
starting at: Sat Jun 8 13:25:12 2019
THE CANDY MACHINE (full with 5 bars)!
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Refilling candy...
OK
Refilling candy...
OK
Refilling candy...
OK
Buying candy...
OK
Refilling candy...
OK
Refilling candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
Buying candy...
OK
网友评论