线程内试图停止自身导致的竞态条件

引发的原因很简单:在一个服务线程内,试图调用停止自身的方法并 join 导致死锁,进而导致线程被阻塞,服务无法正常退出。

伪代码如下:

import threading

class Service:
    def __init__(self, message_handler):
        self._message_handler = message_handler
        self._stop_event = threading.Event()
        self._server_thread = threading.Thread(target=self._start_server)
    
    def _start_server(self):
        while not self._stop_event.is_set():
            # 收到客户端的 message,在回调中处理
            self._message_handler(message)

    def start(self):
        self._server_thread.start()
    
    def stop(self):
        self._stop_event.set()
        self._server_thread.join()

def message_handler(message):
    if message == "stop":
        service.stop() # <-- 这里会导致死锁!

if __name__ == "__main__":
    service = Service(message_handler)
    service.start()

这段代码比较迷惑人的一点是,在实际项目中,Service 往往是在单独的模块中,而被传入的 message_handler 则是在 Service 的调用方。这就容易让人误以为 message_handler 是在调用 Service 的线程执行,但实际是在 Service 自身运行的线程中执行。

由于 message_handler 中调用了 Service.stop,这个方法中又 join 了 Service 所在的线程,从而导致死锁(join 要等到 Service 所在线程结束后返回,但 Service 所在线程又需要等到 join 调用完成后才能结束)。

点此查看原文