Comes from cpython source code:
only the main thread can set a signal handler
any thread can get a signal handler
signals are only delivered to the main thread
This explains what it is doing, but not why it is doing so.
So why only the main thread can set a signal handler and handle signals? Does this come with benefits or due to restrictions?
Related
I read singnal docs of python. It said singale handler must be registered in main thread.
If I start a thread (grand father) which start a child thread (father) which start another thread (grandson)
Does the father thread a main thread compared to grandson?
No. There is only one main thread. It is the thread which is running at program startup.
You can check which thread your code is running on with threading.current_thread() == threading.main_thread().
The signal.signal() documentation states:
When threads are enabled, this function can only be called from the main thread of the main interpreter; attempting to call it from other threads will cause a ValueError exception to be raised.
So, the best way to use this function would be to set up your signal handler before starting any threads.
Note that the documentation also says:
Python signal handlers are always executed in the main Python thread of the main interpreter, even if the signal was received in another thread. This means that signals can’t be used as a means of inter-thread communication.
If i understand the question correctly;
No, the grandson is not tracked by the mainthread inheritly. Although there are different ways you can start threads, one that is dependent on that the child thread is finished and closed before closing the parent or the parent continues in parallell.
But stating in the general case, the father is "owned" by the main thread while the child is "owned" by the father.
In python's signal handling semantics, only main thread can set signal handler, and only main thread can invoke signal handler.
Why design like this?
This comment appears in the cpython sourcefile signalmodule.c:
/* NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS
When threads are supported, we want the following semantics:
only the main thread can set a signal handler
any thread can get a signal handler
signals are only delivered to the main thread
I.e. we don't support "synchronous signals" like SIGFPE (catching
this doesn't make much sense in Python anyway) nor do we support
signals as a means of inter-thread communication, since not all
thread implementations support that (at least our thread library
doesn't).
We still have the problem that in some implementations signals
generated by the keyboard (e.g. SIGINT) are delivered to all
threads (e.g. SGI), while in others (e.g. Solaris) such signals are
delivered to one random thread (an intermediate possibility would
be to deliver it to the main thread -- POSIX?). For now, we have a
working implementation that works in all three cases -- the handler
ignores signals if getpid() isn't the same as in the main thread.
XXX This is a hack.
*/
My reading of this is that the limitation on setting signal handlers is to simplify the implmentation of signal handling in cpython, by avoiding having to cope with differences in os-level signal implementations.
Because Python signal module implement it that way. I believe partly because there is no easy way(if any) to lock GIL from non-main thread by signal handler. So I would rather say it's GIL limitation.
You might be interested in this: http://www.dabeaz.com/python/UnderstandingGIL.pdf
I follow MVC design. I have three Controller parts which runs in main GUI thread. Also have another worker thread which processed some I/O stuffs. Once the worker thread finishes its task, all three controllers should get notification. Can anyone suggest me a solution for this ?
I am using PyQT. So is there any way like; subscribe the events from a worker thread to multiple controller parts ?
The easiest way is to just emit a signal in the worker thread. Create three connections from the worker thread's signal to the controllers' slots, and you should be good to go.
Signal/slot connections in Qt are thread-safe and will work as expected. Only the thread in which the object with the slot lives in needs to have an event loop, which is fine, since in your case the slots belong to the controller, which is in the GUI thread which has an event loop.
See the documentation on QObjects and threads for more details.
I have a class that inherits from threading.Thread.
After processing an item from a queue I want it to call a function that I handed over to the thread when starting it. Doing that callback from the run-Method will have it run in my worker thread. Is there a way to run that callback inside the MainThread?
Thanks & Greetings,
Sean
You didnt mention intially that you are using pyqt. Qt has signals and slots built in just for this purpose. If you are launching your thread using QThread then it has the 'finished' signal that your main thread can be connected to on a slot. If you need even more control of the resulting signal you can emit a custom one from the thread with any value you want. When you construct the thread just connect its signal to the slot that you want to act as the callback.
Otherwise you would be blocking your main event loop if you are specifically waiting on the thread.
Here is a link specifically about the new style signal/slots: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/new_style_signals_slots.html
It makes it extremely easy now to create a python signal with whatever signature you want and connect it in an object oriented fashion to a slot.
Also as a side note about PyQt... Some of the other answers here have suggested creating a loop on your main thread that waits to collect responses in a queue from its dispatched threads. That is essentially what PyQt does. When you start your app the main thread goes into an event loop. This event loop is processing events that stack up in its event queue. There are different types of signal/slot connections. If your two endpoints are in the same thread, then a direct connection will be made and the emitting signal will call the slot. If they are in different threads, then I believe it goes through the event loop so that it can be processed outside of the emitters thread.
Push the method onto a queue and have the main thread sit and wait on that queue, running each method as it pulls them off.
You can use condition variables and have your main thread wait on a message from the sub-thread. The sub-thread can signal the main thread to call that method.
What are the rules surrounding Python threads and how Unix signals are handled?
Is KeyboardInterrupt, which is triggered by SIGINT but handled internally by the Python runtime, handled differently?
First, when setting up signal handlers using the signal module, you must create them in the main thread. You will receive an exception if you try to create them in a separate thread.
Signal handlers registered via the signal.signal() function will always be called in the main thread. On architectures which support sending signals to threads, at the C level I believe the Python runtime ignores all signals on threads and has a signal handler on the main thread, which it uses to dispatch to your Python-code signal handler.
The documentation for the thread module states that the KeyboardInterrupt exception (which is ordinarily triggered by SIGINT) can be delivered to an arbitrary thread unless you have the signal module available to you, which all Unix systems should have. In that case, it's delivered to the main thread. If you're on a system without signal, you'll have to catch KeyboardInterrupt in your thread and call thread.interrupt_main() to re-raise it in the main thread.
More information can be found in the Python docs for the thread and signal modules.
From the signal documentation:
Some care must be taken if both signals and threads are used in the same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform signal() operations in the main thread of execution. Any thread can perform an alarm(), getsignal(), pause(), setitimer() or getitimer(); only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Python signal module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can’t be used as a means of inter-thread communication. Use locks instead.