听起来好像当前线程派生时,该进程中所有锁的状态都已复制到子进程中(这似乎是设计错误,并且肯定会死锁)。
这不是设计错误,而是fork()
早于单进程多线程。所有锁的状态都被复制到子进程中,因为它们只是内存中的对象。进程的整个地址空间都按fork复制。仅有一些不好的选择:要么通过fork复制所有 线程,要么拒绝多线程应用程序中的派生。
因此,fork()
除非在子进程之后execve()
或exit()
在子进程中进行操作,否则永远都不是安全的事情。
是否可以在各处用multiprocessing.Lock替换threading.Lock来避免此问题,并允许我们安全地组合线程和fork?
没有什么可以安全地组合线程和派生的,这是无法做到的。
问题是,当一个进程中有多个线程时,在fork()
系统调用之后,您将无法继续在POSIX系统中安全地运行该程序。
例如,Linux手册fork(2)
:
* 在fork(2)
进入多线程程序之后,子级只能安全地调用异步信号安全函数(请参阅参考资料signal(7)
),直到它调用为止execve(2)
。
也就是说,可以fork()
在多线程程序中然后仅调用异步信号安全的 函数(这是 函数的相当有限的子集),直到子进程已被另一个可执行文件替换!
因此,子进程实际上可以安全地执行的操作很少。不幸的是,cpython核心开发人员一直低估了由此引起的问题。甚至现在文档说:
请注意,安全地分叉多线程进程是 。
委婉的说法是“不可能”。
如果您 不 使用start方法,则可以安全地 从 具有多个控制线程的Python进程中使用多重处理。在Python 3.4+中,@L_301_4@。在包括所有Python 2在内的早期Python版本中,POSIX系统始终表现为被指定为启动方法。这将导致不确定的行为。 __fork
fork
问题不仅限于threading.Lock
对象,还包括C标准库,C扩展等持有的 锁。更糟糕的是,大多数时候人们会说“它对 ” …直到它停止工作。
甚至在某些情况下,看似单线程的Python程序实际上在MacOS X中是多线程的,在使用多处理时会导致失败和死锁。
另一个问题是,所有打开的文件句柄,它们的使用,共享套接字在派生的程序中可能表现得很奇怪,但是即使在单线程程序中也是如此。
TL; DR:multiprocessing
在多线程程序中使用,带有C扩展名,打开的套接字等: