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 closed. The 2nd process is always processing and ideally should emit signal(s) to specific slot(s) in the GUI in an asynchronous manner.
Question: Which approach/tools are available in Python and PyQt4 to achieve that and how? Preferably in a soft-interrupt manner rather than polling.
Abstractly speaking, the solution I can think of is a "tool/handler" instantiated in the main thread that grabs the available slots from the GUI instance and connects with the grabbed signals from the 2nd process, assuming I provide this tool some information of what to expect or hard coded. This could be instantiated to a 3rd process/thread.
This is an example Qt application demonstrating sending signals from a child process to slots in the mother process. I'm not sure this is right approach but it works.
I differentiate between process as mother and child, because the word parent is alread used in the Qt context.
The mother process has two threads. Main thread of mother process sends data to child process via
multiprocessing.Queue
. Child process sends processed data and signature of the signal to be sent to the second thread of mother process viamultiprocessing.Pipe
. The second thread of mother process actually emits the signal.Python 2.X, PyQt4:
And as convenience also Python 3.X, PySide:
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 ofConnection
is non-blocking, therefore I would regularly poll it with aQTimer
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 aQueue
with theget
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 aThread
who listens on aConnection
and upon a certain message, closes the GUI which then terminates the process.I had the same problem in C++. From a QApplication, I spawn a Service object. The object creates the Gui Widget but it's not its parent (the parent is QApplication then). To control the GuiWidget from the service widget, I just use signals and slots as usual and it works as expected. Note: The thread of GuiWidget and the one of the service are different. The service is a subclass of QObject.
If you need multi process signal/slot mechanism, then try to use Apache Thrift or use a Qt-monitoring process which spawns 2 QProcess objects.
Hy all,
I hope this is not considered to much of a necro-dump however I thought it would be good to update Nizam's answer by adding updating his example to PyQt5, adding some comments, removing some python2 syntax and most of all by using the new style of signals available in PyQt. Hope someone finds it useful.
A quite interesting topic. I guess having a signal that works between threads is a very useful thing. How about creating a custom signal based on sockets? I haven't tested this yet, but this is what I gathered up with some quick investigation:
Might just put you on the right track.