Context: In Python a main thread spawns a 2nd process (using multiprocessing module) and then launches a GUI (using PyQt4). At this point the main thread blocks until the GUI is
One should first look how Signals/Slots work within only one Python process:
If there is only one running QThread, they just call the slots directly.
If the signal is emitted on a different thread it has to find the target thread of the signal and put a message/ post an event in the thread queue of this thread. This thread will then, in due time, process the message/event and call the signal.
So, there is always some kind of polling involved internally and the important thing is that the polling is non-blocking.
Processes created by multiprocessing can communicate via Pipes which gives you two connections for each side.
The poll function of Connection is non-blocking, therefore I would regularly poll it with a QTimer and then emit signals accordingly.
Another solution might be to have a Thread from the threading module (or a QThread) specifically just waiting for new messages from a Queue with the get function of the queue. See the Pipes and Queues part of multiprocessing for more information..
Here is an example starting a Qt GUI in another Process together with a Thread who listens on a Connection and upon a certain message, closes the GUI which then terminates the process.
from multiprocessing import Process, Pipe
from threading import Thread
import time
from PySide import QtGui
class MyProcess(Process):
def __init__(self, child_conn):
super().__init__()
self.child_conn = child_conn
def run(self):
# start a qt application
app = QtGui.QApplication([])
window = QtGui.QWidget()
layout = QtGui.QVBoxLayout(window)
button = QtGui.QPushButton('Test')
button.clicked.connect(self.print_something)
layout.addWidget(button)
window.show()
# start thread which listens on the child_connection
t = Thread(target=self.listen, args = (app,))
t.start()
app.exec_() # this will block this process until somebody calls app.quit
def listen(self, app):
while True:
message = self.child_conn.recv()
if message == 'stop now':
app.quit()
return
def print_something(self):
print("button pressed")
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
s = MyProcess(child_conn)
s.start()
time.sleep(5)
parent_conn.send('stop now')
s.join()