我有以下示例代码,用于在Python中处理条件:
import threading
import random
import time
class Producer(threading.Thread):
"""
Produces random integers to a list
"""
def __init__(self, integers, condition):
"""
Constructor.
@param integers list of integers
@param condition condition synchronization object
"""
threading.Thread.__init__(self)
self.integers = integers
self.condition = condition
def run(self):
"""
Thread run method. Append random integers to the integers list
at random time.
"""
while True:
integer = random.randint(0, 256)
self.condition.acquire()
print 'condition acquired by %s' % self.name
self.integers.append(integer)
print '%d appended to list by %s' % (integer, self.name)
print 'condition notified by %s' % self.name
self.condition.notify()
print 'condition released by %s' % self.name
self.condition.release()
time.sleep(1)
class Consumer(threading.Thread):
"""
Consumes random integers from a list
"""
def __init__(self, integers, condition):
"""
Constructor.
@param integers list of integers
@param condition condition synchronization object
"""
threading.Thread.__init__(self)
self.integers = integers
self.condition = condition
def run(self):
"""
Thread run method. Consumes integers from list
"""
while True:
self.condition.acquire()
print 'condition acquired by %s' % self.name
while True:
if self.integers:
integer = self.integers.pop()
print '%d popped from list by %s' % (integer, self.name)
break
print 'condition wait by %s' % self.name
self.condition.wait()
print 'condition released by %s' % self.name
self.condition.release()
def main():
integers = []
condition = threading.Condition()
t1 = Producer(integers, condition)
t2 = Consumer(integers, condition)
t1.start()
t2.start()
t1.join()
t2.join()
if __name__ == '__main__':
main()
根据我的理解,当消费者调用wait()
方法时,它将释放条件并进入睡眠状态。
当生产者在调用notify()
之后通知线程时,似乎没有一个消费者在尝试从整数列表中弹出之前都没有重新获得条件。
这不是比赛条件吗?
答案 0 :(得分:1)
消费者从wait()
唤醒后无需重新获取条件,因为他们直到从wait()
恢复后才释放它。
它们释放的是始终与条件(无论是显式的还是隐式的)相关联的锁。
来自docs:
条件变量总是与某种锁相关联;可以传入,也可以默认创建一个。 [...] 锁是条件对象的一部分:您不必单独跟踪它。
通过获取/释放条件以及在调用wait()
resp时隐式获取和释放锁。从它醒来。
acquire()和release()方法还调用关联锁的相应方法。
[..]
wait()方法释放该锁,然后阻塞,直到另一个线程通过调用notify()或notify_all()将其唤醒。唤醒后,wait()重新获取锁并返回。
因此,始终最多可以有一个线程持有该锁,从而可以在任何给定的时间点安全地修改共享资源。