Python中其他线程能否释放另一线程持有的锁?
关于Python多线程中跨线程释放锁的疑问
我正在学习Python多线程技术,看到如下生产者消费者问题的示例代码:
import random import logging import threading import concurrent.futures SENTINEL = object() def producer(pipeline): """Pretend we're getting a message from the network.""" for index in range(10): message = random.randint(1, 101) logging.info("Producer got message: %s", message) pipeline.set_message(message, "Producer") # Send a sentinel message to tell consumer we're done pipeline.set_message(SENTINEL, "Producer") def consumer(pipeline): """Pretend we're saving a number in the database.""" message = 0 while message is not SENTINEL: message = pipeline.get_message("Consumer") if message is not SENTINEL: logging.info("Consumer storing message: %s", message) if __name__ == "__main__": format = "%(asctime)s: %(message)s" logging.basicConfig(format=format, level=logging.INFO, datefmt="%H:%M:%S") # logging.getLogger().setLevel(logging.DEBUG) pipeline = Pipeline() with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: executor.submit(producer, pipeline) executor.submit(consumer, pipeline) class Pipeline: """ Class to allow a single element pipeline between producer and consumer. """ def __init__(self): self.message = 0 self.producer_lock = threading.Lock() self.consumer_lock = threading.Lock() self.consumer_lock.acquire() def get_message(self, name): logging.debug("%s:about to acquire getlock", name) self.consumer_lock.acquire() logging.debug("%s:have getlock", name) message = self.message logging.debug("%s:about to release setlock", name) self.producer_lock.release() logging.debug("%s:setlock released", name) return message def set_message(self, message, name): logging.debug("%s:about to acquire setlock", name) self.producer_lock.acquire() logging.debug("%s:have setlock", name) self.message = message logging.debug("%s:about to release getlock", name) self.consumer_lock.release() logging.debug("%s:getlock released", name)
我的疑问是:consumer_lock和producer_lock分别由不同线程获取和释放,这是否可行?我感觉自己有所遗漏,因为如果可以的话,那是不是任意线程都能释放其他线程持有的锁?
解答
- Python的
threading.Lock确实允许任意线程释放锁,不管该线程是否是锁的持有者,这是它的设计特性,和Java等语言中必须由持有锁的线程释放锁的机制不同。 - 这段代码的写法是可行的,它通过两个锁的交替锁定/释放,实现了生产者和消费者的严格同步:
- 初始化时主线程先获取
consumer_lock,导致消费者一开始调用get_message时会阻塞在consumer_lock.acquire()。 - 生产者首次调用
set_message时,能顺利获取未锁定的producer_lock,设置消息后释放consumer_lock,唤醒消费者读取消息。 - 消费者读取完消息后释放
producer_lock,让生产者可以再次获取锁生产下一条消息。 - 如此循环,确保生产一个消息后必须等待消费完成,才能生产下一个,避免了竞态条件。
- 初始化时主线程先获取
不过需要注意:这种跨线程释放锁的写法对逻辑严谨性要求极高,稍有不慎就会引发死锁或同步错误。在实际开发中,更推荐使用Python标准库提供的queue.Queue(已封装完善的同步逻辑),或者threading.Condition实现等待/通知机制,代码可读性和安全性都会更好。
内容的提问来源于stack exchange,提问作者Victor M
相关产品推荐
相关产品推荐

