mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Issue #14456: improve documentation of the signal module w.r.t. threads.
This commit is contained in:
commit
682d443e01
1 changed files with 59 additions and 36 deletions
|
@ -5,43 +5,61 @@
|
||||||
:synopsis: Set handlers for asynchronous events.
|
:synopsis: Set handlers for asynchronous events.
|
||||||
|
|
||||||
|
|
||||||
This module provides mechanisms to use signal handlers in Python. Some general
|
This module provides mechanisms to use signal handlers in Python.
|
||||||
rules for working with signals and their handlers:
|
|
||||||
|
|
||||||
* A handler for a particular signal, once set, remains installed until it is
|
|
||||||
|
General rules
|
||||||
|
-------------
|
||||||
|
|
||||||
|
The :func:`signal.signal` function allows to define custom handlers to be
|
||||||
|
executed when a signal is received. A small number of default handlers are
|
||||||
|
installed: :const:`SIGPIPE` is ignored (so write errors on pipes and sockets
|
||||||
|
can be reported as ordinary Python exceptions) and :const:`SIGINT` is
|
||||||
|
translated into a :exc:`KeyboardInterrupt` exception.
|
||||||
|
|
||||||
|
A handler for a particular signal, once set, remains installed until it is
|
||||||
explicitly reset (Python emulates the BSD style interface regardless of the
|
explicitly reset (Python emulates the BSD style interface regardless of the
|
||||||
underlying implementation), with the exception of the handler for
|
underlying implementation), with the exception of the handler for
|
||||||
:const:`SIGCHLD`, which follows the underlying implementation.
|
:const:`SIGCHLD`, which follows the underlying implementation.
|
||||||
|
|
||||||
* Although Python signal handlers are called asynchronously as far as the Python
|
There is no way to "block" signals temporarily from critical sections (since
|
||||||
user is concerned, they can only occur between the "atomic" instructions of the
|
this is not supported by all Unix flavors).
|
||||||
Python interpreter. This means that signals arriving during long calculations
|
|
||||||
implemented purely in C (such as regular expression matches on large bodies of
|
|
||||||
text) may be delayed for an arbitrary amount of time.
|
|
||||||
|
|
||||||
* When a signal arrives during an I/O operation, it is possible that the I/O
|
|
||||||
operation raises an exception after the signal handler returns. This is
|
|
||||||
dependent on the underlying Unix system's semantics regarding interrupted system
|
|
||||||
calls.
|
|
||||||
|
|
||||||
* Because the C signal handler always returns, it makes little sense to catch
|
Execution of Python signal handlers
|
||||||
synchronous errors like :const:`SIGFPE` or :const:`SIGSEGV`.
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
* Python installs a small number of signal handlers by default: :const:`SIGPIPE`
|
A Python signal handler does not get executed inside the low-level (C) signal
|
||||||
is ignored (so write errors on pipes and sockets can be reported as ordinary
|
handler. Instead, the low-level signal handler sets a flag which tells the
|
||||||
Python exceptions) and :const:`SIGINT` is translated into a
|
:term:`virtual machine` to execute the corresponding Python signal handler
|
||||||
:exc:`KeyboardInterrupt` exception. All of these can be overridden.
|
at a later point(for example at the next :term:`bytecode` instruction).
|
||||||
|
This has consequences:
|
||||||
|
|
||||||
* Some care must be taken if both signals and threads are used in the same
|
* It makes little sense to catch synchronous errors like :const:`SIGFPE` or
|
||||||
program. The fundamental thing to remember in using signals and threads
|
:const:`SIGSEGV`.
|
||||||
simultaneously is: always perform :func:`signal` operations in the main thread
|
|
||||||
of execution. Any thread can perform an :func:`alarm`, :func:`getsignal`,
|
* A long-running calculation implemented purely in C (such as regular
|
||||||
:func:`pause`, :func:`setitimer` or :func:`getitimer`; only the main thread
|
expression matching on a large body of text) may run uninterrupted for an
|
||||||
can set a new signal handler, and the main thread will be the only one to
|
arbitrary amount of time, regardless of any signals received. The Python
|
||||||
receive signals (this is enforced by the Python :mod:`signal` module, even
|
signal handlers will be called when the calculation finishes.
|
||||||
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.
|
.. _signals-and-threads:
|
||||||
|
|
||||||
|
|
||||||
|
Signals and threads
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Python signal handlers are always executed in the main Python thread,
|
||||||
|
even if the signal was received in another thread. This means that signals
|
||||||
|
can't be used as a means of inter-thread communication. You can use
|
||||||
|
the synchronization primitives from the :mod:`threading` module instead.
|
||||||
|
|
||||||
|
Besides, only the main thread is allowed to set a new signal handler.
|
||||||
|
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
The variables defined in the :mod:`signal` module are:
|
The variables defined in the :mod:`signal` module are:
|
||||||
|
|
||||||
|
@ -189,15 +207,20 @@ The :mod:`signal` module defines the following functions:
|
||||||
|
|
||||||
.. function:: pthread_kill(thread_id, signum)
|
.. function:: pthread_kill(thread_id, signum)
|
||||||
|
|
||||||
Send the signal *signum* to the thread *thread_id*, another thread in the same
|
Send the signal *signum* to the thread *thread_id*, another thread in the
|
||||||
process as the caller. The signal is asynchronously directed to thread.
|
same process as the caller. The target thread can be executing any code
|
||||||
|
(Python or not). However, if the target thread is executing the Python
|
||||||
|
interpreter, the Python signal handlers will be :ref:`executed by the main
|
||||||
|
thread <signals-and-threads>`. Therefore, the only point of sending a signal to a particular
|
||||||
|
Python thread would be to force a running system call to fail with
|
||||||
|
:exc:`InterruptedError`.
|
||||||
|
|
||||||
Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident`
|
Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident`
|
||||||
attribute of :attr:`threading.Thread` to get a 'thread identifier' for
|
attribute of :class:`threading.Thread` objects to get a suitable value
|
||||||
*thread_id*.
|
for *thread_id*.
|
||||||
|
|
||||||
If *signum* is 0, then no signal is sent, but error checking is still
|
If *signum* is 0, then no signal is sent, but error checking is still
|
||||||
performed; this can be used to check if a thread is still running.
|
performed; this can be used to check if the target thread is still running.
|
||||||
|
|
||||||
Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
|
Availability: Unix (see the man page :manpage:`pthread_kill(3)` for further
|
||||||
information).
|
information).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue