我正在阅读“信号量小书”,其中有一些代码可以让python使用与他在本书中使用的语法类似的语法。但是,当我尝试导入他的代码时,它会给我以下错误。
from threading_cleanup import *
RuntimeError: not holding the import lock
我知道它与观察者功能代码有关,因为如果我将其注释掉,那么错误就会消失,那里的代码就可以了,所以我可以使用KeyboardInterrupt结束程序。
有没有办法解决错误?
import threading
import time
import os
import signal
import sys
__all__ = ['Thread', 'Semaphore', 'watcher']
class Thread(threading.Thread):
def __init__(self, target, *args):
threading.Thread.__init__(self, target=target, args=args)
self.start()
class Semaphore(threading._Semaphore):
wait = threading._Semaphore.acquire
def signal(self, n=1):
for _ in range(n): self.release()
def value(self):
return self._Semaphore__value
def watcher():
child = os.fork()
if child == 0: return
try:
os.wait()
except KeyboardInterrupt:
print 'KeyboardInterrupt'
os.kill(child, signal.SIGKILL)
sys.exit()
watcher()
答案 0 :(得分:1)
在我的设置中,错误仅在解释模式下发生。
似乎解释器不喜欢模块在仍然导入时执行分叉。
如果您移除watcher()
电话或将其包裹在if __name__ == '__main__':
中,则错误消失。
通常,Python模块执行的代码应仅用于初始化全局变量和单例。
哦!导入后,您可以从解释器中调用threading_cleanup.watcher()
,并且不会引发异常。
哎!我意识到我没有回答你问题的标题:
对fork()
的调用会创建一个新的解释程序;一个必须导入模块才能开始执行的模块。在解释模式下,您在模块仍在导入时会发生这种情况,从而被锁定。在解释模式中,交互式解释器是主程序。在执行模式下,如在python mymodule.py
中,模块是主程序,因此它不会导入。这有意义吗?
答案 1 :(得分:0)
这个问题的标题询问进口锁是什么。
导入锁是Python的import
实现的一部分,如果你违反了这些模糊的限制,会导致程序失败:
https://docs.python.org/2/library/threading.html#importing-in-threaded-code
在您的情况下,因为您直接在模块中调用watcher()
,所以除非该模块恰好是主模块,否则它无法启动线程。这是一个例子:
python2.7 - import silently locks up the thread
您的示例似乎有点不同,因为它涉及进程。如果我将threading_cleanup.py
缩减为:
import os
def watcher():
child = os.fork()
watcher()
我仍然得到同样的错误:
File "main.py", line 1, in <module>
import threading_cleanup.py
RuntimeError: not holding the import lock
所以,这不是一个进口锁。除了错误消息说它是一个导入锁,现在不是吗?听起来像错误消息文本中的错误。