Why am I unable to run a PySide GUI in a spawned child process?
-
I just posted this to stackoverflow, but perhaps someone here will be able to help.
I'm attempting to run a PySide GUI in a spawned child process, but it keeps exiting with exitcode 11 (segfault). This simplified test code works fine if run_gui is called directly, but fails if it's run inside a child process:
@# std lib imports
import time
import sys
from multiprocessing import Processthird party imports
from PySide.QtGui import QApplication, QMainWindow
def run_gui():
app = QApplication([])
w = QMainWindow()
w.show()
w.raise_()
sys.exit(app.exec_())def main():
gui_proc = Process(target=run_gui)
#gui_proc.daemon = True # this doesn't seem to matter
gui_proc.start()
while True:
if not gui_proc.is_alive():
if gui_proc.exitcode != 0:
print 'GUI exited with code {}'.format(gui_proc.exitcode)
else:
print 'GUI exited cleanly.'
break
time.sleep(1)if name == "main":
## GUI in main process:
#run_gui()
## GUI in child process:
main()@Is there a way around this? I'm not sure how to debug what's causing the segfault.
The reason I'm interested in doing this is so that I can restart the GUI if it crashes unexpectedly, all the while keeping a couple daemon processes running (one for disk access and another for interacting with instruments).
I also tried another test script (below) using QCoreApplication and no GUI, and I see the same problem. Apparently PySide just won't run in a child process.
@# std lib imports
import time
import sys
from multiprocessing import Processthird party imports
from PySide.QtCore import QCoreApplication, QTimer
def quit():
print "Quiting..."
sys.exit()def run():
app = QCoreApplication([])
timer = QTimer()
timer.timeout.connect(quit)
timer.start(1000)
print "Starting..."
sys.exit(app.exec_())def main():
proc = Process(target=run)
#proc.daemon = True # this doesn't seem to matter
proc.start()
while True:
if not proc.is_alive():
print 'Process exited with code {}'.format(proc.exitcode)
break
time.sleep(1)if name == "main":
## GUI in main process:
#run()
## GUI in child process:
main()@ -
My experience (with PyQt) is that Qt doesn't always play nice with Python's multiprocessing module. I found that using QProcess to start and manage the GUI was the most reliable way.
@
...
p=QProcess()
p.start("python", ["mygui.py"])
...
@Hope this helps :o)
-
Thanks for the response! I may end up going the QProcess or subprocess route if I absolutely have to, but I'm currently making use of multiprocessing.Pipe, and I would greatly prefer not having to reimplement those features.
-
I ended up using QLocalServer/Socket in place of pipes, which at least allows the use of the signal/slot mechanism, though I appreciate the reluctance to reimplement things.
-
Ahh, I didn't know about QLocalServer. I had originally looked at using python's socket library, but I didn't think about checking out Qt's. If it transparently handles signal/slots that might be the easiest approach. I'll give it a shot. Thanks!
Edit: Okay, it looks like it doesn't handle signal/slots in the way I thought you meant. It doesn't transparently send them over the network. There does appear to be a third party library for that (QxtRPCPeer), but it doesn't have python bindings. I guess I'm stuck either going without a child GUI process or reimplementing the functionality provided by multiprocessing.Pipe.