Since this three-year-old discussion we've added a couple of post-fork-cleanups to CPython (the TLS, the threading module's idea of active threads, see Modules/signalmodule.c:PyOS_AfterFork) and we already do simply discard the memory for other locks held during fork (the GIL, see Python/ceval.c:PyEval_ReInitThreads, and the TLS lock in Python/thread.c:PyThread_ReInitTLS) -- but not so with the import lock, except when the platform is AIX. I don't see any particular reason why we aren't doing the same thing to the import lock that we do to the other locks, on all platforms. It's a quick fix for a real problem (see
On Thu, May 18, 2006 at 20:02, "Martin v. Löwis" <email@example.com>
Nick Coghlan wrote:Right. With some googling, I found that one solution is pthread_atexit:
> And if I understand it correctly, it falls under the category that
> waiting for another thread while holding the import lock is a *really*
> bad idea from a thread safety point of view.
> The thing with the import-after-fork deadlock is that you can trigger it
> without even doing anything that's known not to be thread-safe.
a pthread_atexit handler is a triple (before, in_parent, in_child).
You set it to (acquire, release, release). When somebody forks,
the pthread library will first acquire the import lock in the thread
that wants to fork. Then the fork occurs, and the import lock gets
then released both in the parent and in the child.
I would like to see this approach implemented, but I agree with you
that a test case should be created first.
Picking up a rather old discussion... We encountered this bug at Google and I'm now "incentivized" to fix it.
For a short recap: Python has an import lock that prevents more than one thread from doing an import at any given time. However, unlike most of the locks we have lying around, we don't clear that lock in the child after an os.fork(). That means that doing an os.fork() during an import means the child process can't do any other imports. It also means that doing an os.fork() *while another thread is doing an import* means the child process can't do any other imports.