You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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等语言中必须由持有锁的线程释放锁的机制不同。
  • 这段代码的写法是可行的,它通过两个锁的交替锁定/释放,实现了生产者和消费者的严格同步:
    1. 初始化时主线程先获取consumer_lock,导致消费者一开始调用get_message时会阻塞在consumer_lock.acquire()。
    2. 生产者首次调用set_message时,能顺利获取未锁定的producer_lock,设置消息后释放consumer_lock,唤醒消费者读取消息。
    3. 消费者读取完消息后释放producer_lock,让生产者可以再次获取锁生产下一条消息。
    4. 如此循环,确保生产一个消息后必须等待消费完成,才能生产下一个,避免了竞态条件。

不过需要注意:这种跨线程释放锁的写法对逻辑严谨性要求极高,稍有不慎就会引发死锁或同步错误。在实际开发中,更推荐使用Python标准库提供的queue.Queue(已封装完善的同步逻辑),或者threading.Condition实现等待/通知机制,代码可读性和安全性都会更好。

内容的提问来源于stack exchange,提问作者Victor M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:12:58