在此信号量示例中,是否有必要锁定refill()和buy()?
书中说:
当虚拟售货商的所有者在以下情况下执行refill()函数:
机器开始向库存添加另外一项。整个程序
代表关键部分;这就是为什么获取锁是唯一的方法
执行所有行。
但我认为有必要锁定refill()和buy()
您的意见呢?
#!/usr/bin/env python
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():
# lock.acquire()
try:
candytray.release()
except ValueError:
pass
#lock.release()
def buy():
#lock.acquire()
candytray.acquire(False)
#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() # buyer
Thread(target=producer, args=(nloops,)).start() # vendor
@register
def _atexit():
print('all DONE at:', ctime())
if __name__ == '__main__':
_main()
最佳答案
锁是绝对必要的。如果您稍稍更改代码以打印每次生产者/消费者调用后剩余的糖果数量,这可能会有所帮助。替换了信号量,因为它所做的只是保持计数。
我加了
numcandies = 5
补充:
def refill():
global numcandies
numcandies += 1
print ("Refill: %d left" % numcandies)
购买:
def buy():
global numcandies
numcandies -= 1
print("Buy: %d left" %numcandies)
这是不带锁的输出(显示数据争用问题)。
('starting at:', 'Tue Mar 26 23:09:41 2013')
THE CANDY MACHINE (full with 5 bars)!
Buy: 4 left
Refill: 5 left
Refill: 6 left
Buy: 5 left
Buy: 4 left
Buy: 3 left
Refill: 6 left
Refill: 7 left
Buy: 6 left
('all DONE at:', 'Tue Mar 26 23:09:43 2013')
在
producer
调用与numcandies
计数器的实际更新之间的某个位置,我们连续两次调用consumer
。没有锁定,就无法控制谁实际修改了计数器的顺序。因此,在上述情况下,即使
numcandies
更新为3购买consumer
,producer
仍然具有5的本地副本。更新后,它将计数器设置为6,这是完全错误的。