This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: ctypes issue with threads after fork
Type: Stage:
Components: Interpreter Core Versions: Python 3.4, Python 3.5
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Andre Merzky, Chase Sterling, Steven Adams, amaury.forgeotdarc, belopolsky, meador.inge, serhiy.storchaka, vstinner, xiang.zhang
Priority: normal Keywords:

Created on 2016-04-18 04:51 by Steven Adams, last changed 2022-04-11 14:58 by admin.

Messages (16)
msg263640 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-18 04:51
I've ran into a strange issue after trying to port a project to support py 3.x

The app uses a double os.fork to run in the background. On py 3.4+ it seems that when you have an import uuid statement it causes threading.threads to always return false on is_alive()..

Here is an example of the issue. You can see i've imported uuid. This script should fork into the background and stay alive for at least 3 loops (3 seconds) but it dies after 1 loop as self._thread.is_alive() return False??

http://paste.pound-python.org/show/WbDkqPqu94zEstHG6Xl1/

This does NOT happen in py 2.7 or py3.3. Only occurs py3.4+
msg263641 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-18 04:54
I forgot to mention if i remove import uuid all works as expected.
msg263644 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-04-18 05:48
It seems a matter of lib uuid. The comments in uuid.py tells that the module is not thread-safe. I try to comment out the code using ctypes and rerun your sample, it works well. 

In uuid's documentation it does not mention the non-thread-safe characteristic. Maybe we should add it.
msg263645 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-18 05:53
Shouldn't that mean it also breaks on py3.3?

As a workaround i just import uuid later within the thread method.
msg263646 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-04-18 06:14
Sorry. I forgot to take that into consideration. I think now the problem appears because of ctypes. Simply import ctypes instead of uuid can also lead to your problem.
msg263648 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-18 07:03
My workaround didn't work either.. We are a number of third party libs including flask. As soon as i import flask the issues remains.. Maybe something with flask is importing ctypes?

Something aint right..
msg263649 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-04-18 07:08
I am not sure what the real problem is. What I can see now it that it seems ctypes affects process fork. If you create the thread after fork, for example, in wait, your example works well. But if the thread participates in process fork, it fails.
msg263650 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2016-04-18 07:20
IMHO it's a bad idea to create a thread before forking. I suggest you to not create any kind of resource before calling daemonize().
msg263651 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-04-18 07:29
I write a simple example which behaviour is like Steven's example.

import os
import sys
import threading
import ctypes
import time

def test():
    while True:
        print(time.time())

_thread = threading.Thread(target=test)

pid = os.fork()
if pid > 0:
    sys.exit(0)

_thread.start()

Run this with py3.4 emits one print and then comes fatal error:

[code]$ python3 ctypes_test.py 
1460964519.9721818
[code]$ Fatal Python error: could not acquire lock for <_io.BufferedWriter name='<stdout>'> at interpreter shutdown, possibly due to daemon threads

Thread 0x00007f41fdadf700 (most recent call first):
  File "ctypes_test.py", line 9 in test
  File "/usr/lib/python3.4/threading.py", line 868 in run
  File "/usr/lib/python3.4/threading.py", line 920 in _bootstrap_inner
  File "/usr/lib/python3.4/threading.py", line 888 in _bootstrap

Current thread 0x00007f41ff9a9700 (most recent call first):
^C

Without import ctypes, it's OK.
msg263655 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2016-04-18 08:21
Hum, I should elaborate my explanation :-) os.fork() removes all threads except of the current thread. It's clearly stated in the fork manual page, but the Python os.fork() doesn't say anything about threads.
https://docs.python.org/dev/library/os.html#os.fork

Short example:
---
import os, threading, time

t = threading.Thread(target=time.sleep, args=(3.0,))
t.start()

print("First process", threading.enumerate())

pid = os.fork()
if pid != 0:
    os.waitpid(pid, 0)
else:
    print("Child process", threading.enumerate())
---

Output:
---
First process [<_MainThread(MainThread, started 140737353955072)>, <Thread(Thread-1, started 140737216849664)>]
Child process [<_MainThread(MainThread, started 140737353955072)>]
---

The thread is removed in the child process.

Again, *don't create threads before fork*. More generally, don't create any resource before fork: don't open files, don't create locks, don't open a connection to a database, don't start an event loop, etc.
msg263656 - (view) Author: Xiang Zhang (xiang.zhang) * (Python committer) Date: 2016-04-18 08:30
I should not make more noise after realizing it's matter of thread and process. Sorry. :-( Except this one. :-)
msg263660 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-18 09:20
Ok but the question still remains, why does it only happen on py3.4+??
msg263786 - (view) Author: Chase Sterling (Chase Sterling) Date: 2016-04-19 22:57
@STINNER Victor Your example is starting a thread before calling fork, the other examples just init a threading.Thread class before the fork (I imagine the OS thread is not created at that point.) Are you saying that just instantiating a threading.Thread class before forking (without actually starting the thread) is bad?
msg264144 - (view) Author: Steven Adams (Steven Adams) Date: 2016-04-25 01:55
anyone got any other thoughts on this??
msg291032 - (view) Author: Andre Merzky (Andre Merzky) * Date: 2017-04-02 11:37
This one might be related:

https://bugs.python.org/issue27889
msg303236 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2017-09-28 13:42
The bpo-11063 is going to rewrite uuid using a C extension to avoid ctypes, but also defer "import ctypes" until we really need it (when the new C extension is not available). I don't think this issue is related to uuid directly, no?

I changed the issue title to: "ctypes issue with threads after fork". Don't hesitate to complete/rewrite the title if you understood the issue :-)
History
Date User Action Args
2022-04-11 14:58:29adminsetgithub: 70980
2017-09-28 13:42:02vstinnersetmessages: + msg303236
title: uuid causing thread issues when forking using os.fork py3.4+ -> ctypes issue with threads after fork
2017-04-02 11:37:57Andre Merzkysetnosy: + Andre Merzky
messages: + msg291032
2016-04-25 01:55:11Steven Adamssetmessages: + msg264144
2016-04-19 22:57:58Chase Sterlingsetnosy: + Chase Sterling
messages: + msg263786
2016-04-18 09:20:57Steven Adamssetmessages: + msg263660
2016-04-18 08:30:13xiang.zhangsetmessages: + msg263656
2016-04-18 08:21:14vstinnersetmessages: + msg263655
2016-04-18 08:10:37serhiy.storchakasetnosy: + serhiy.storchaka
2016-04-18 07:29:36xiang.zhangsetmessages: + msg263651
2016-04-18 07:20:05vstinnersetnosy: + vstinner
messages: + msg263650
2016-04-18 07:08:23xiang.zhangsetmessages: + msg263649
2016-04-18 07:03:52Steven Adamssetmessages: + msg263648
2016-04-18 06:14:17xiang.zhangsetnosy: + amaury.forgeotdarc, belopolsky, meador.inge
messages: + msg263646
2016-04-18 05:53:47Steven Adamssetmessages: + msg263645
2016-04-18 05:48:43xiang.zhangsetnosy: - pitrou
messages: + msg263644
2016-04-18 05:31:18xiang.zhangsetnosy: + pitrou, xiang.zhang
2016-04-18 04:54:07Steven Adamssetmessages: + msg263641
2016-04-18 04:51:59Steven Adamscreate