Reputation: 8537
I'm developing a process scheduler in Python. The idea is to create several threads from the main function and start an external process in each of these threads. The external process should continue to run until either it's finished or the main thread decides to stop it (by sending a kill signal) because the process' CPU time limit is exceeded.
The problem is that sometimes the Popen
call blocks and fails to return. This code reproduces the problem with ~50% probability on my system (Ubuntu 14.04.3 LTS):
import os, time, threading, sys
from subprocess import Popen
class Process:
def __init__(self, args):
self.args = args
def run(self):
print("Run subprocess: " + " ".join(self.args))
retcode = -1
try:
self.process = Popen(self.args)
print("started a process")
while self.process.poll() is None:
# in the real code, check for the end condition here and send kill signal if required
time.sleep(1.0)
retcode = self.process.returncode
except:
print("unexpected error:", sys.exc_info()[0])
print("process done, returned {}".format(retcode))
return retcode
def main():
processes = [Process(["/bin/cat"]) for _ in range(4)]
# start all processes
for p in processes:
t = threading.Thread(target=Process.run, args=(p,))
t.daemon = True
t.start()
print("all threads started")
# wait for Ctrl+C
while True:
time.sleep(1.0)
main()
The output indicates that only 3 Popen()
calls have returned:
Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
started a process
started a process
started a process
all threads started
However, running ps
shows that all four processes have in fact been started!
The problem does not show up when using Python 3.4, but I want to keep Python 2.7 compatibility.
Edit: the problem also goes away if I add some delay before starting each subsequent thread.
Edit 2: I did a bit of investigation and the blocking is caused by line 1308 in subprocess.py
module, which tries to do some reading from a pipe in the parent process:
data = _eintr_retry_call(os.read, errpipe_read, 1048576)
Upvotes: 2
Views: 323
Reputation: 13381
There are a handful of bugs in python 2.7's subprocess
module that can result in deadlock when calling the Popen
constructor from multiple threads. They are fixed in later versions of Python, 3.2+ IIRC.
You may find that using the subprocess32
backport of Python 3.2/3.3's subprocess
module resolves your issue.
*I was unable to locate the link to the actual bug report, but encountered it recently when dealing with a similar issue.
Upvotes: 1