Skip to main content
 首页 » 编程设计

python之在这个信号量示例中,是否有必要为 refill() 和 buy() 锁定

2025年05月04日24lvdongjie

在这个信号量示例中,是否需要为 refill() 和 buy() 锁定?

书中说: refill() 函数在虚构商贩的所有者执行时执行- ing 机器开始向库存中添加一个项目。整个套路 代表关键部分;这就是为什么获取锁是唯一的方法 执行所有行。

但我认为没有必要为 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 计数器的实际更新之间的某处,我们连续调用了 2 次 consumer。

如果没有锁定,就无法控制实际修改计数器的人的顺序。所以在上面的例子中,即使 numcandies 被更新为 3 buy consumer,producer 仍然有一个 5 的本地副本。更新后,它将计数器设置为 6,这是完全错误的。