Issue #6064: Add a `daemon` keyword argument to the threading.Thread
and multiprocessing.Process constructors in order to override the default behaviour of inheriting the daemonic property from the current thread/process.
This commit is contained in:
parent
4bc685752f
commit
0bd4deba38
|
@ -297,7 +297,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the
|
|||
:class:`Process` and exceptions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. class:: Process([group[, target[, name[, args[, kwargs]]]]])
|
||||
.. class:: Process([group[, target[, name[, args[, kwargs]]]]], *, daemon=None)
|
||||
|
||||
Process objects represent activity that is run in a separate process. The
|
||||
:class:`Process` class has equivalents of all the methods of
|
||||
|
@ -312,13 +312,19 @@ The :mod:`multiprocessing` package mostly replicates the API of the
|
|||
:sub:`1`,N\ :sub:`2`,...,N\ :sub:`k` is a sequence of integers whose length
|
||||
is determined by the *generation* of the process. *args* is the argument
|
||||
tuple for the target invocation. *kwargs* is a dictionary of keyword
|
||||
arguments for the target invocation. By default, no arguments are passed to
|
||||
*target*.
|
||||
arguments for the target invocation. If provided, the keyword-only *daemon* argument
|
||||
sets the process :attr:`daemon` flag to ``True`` or ``False``. If ``None``
|
||||
(the default), this flag will be inherited from the creating process.
|
||||
|
||||
By default, no arguments are passed to *target*.
|
||||
|
||||
If a subclass overrides the constructor, it must make sure it invokes the
|
||||
base class constructor (:meth:`Process.__init__`) before doing anything else
|
||||
to the process.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *daemon* argument.
|
||||
|
||||
.. method:: run()
|
||||
|
||||
Method representing the process's activity.
|
||||
|
|
|
@ -241,7 +241,7 @@ changed through the :attr:`name` attribute.
|
|||
A thread can be flagged as a "daemon thread". The significance of this flag is
|
||||
that the entire Python program exits when only daemon threads are left. The
|
||||
initial value is inherited from the creating thread. The flag can be set
|
||||
through the :attr:`daemon` property.
|
||||
through the :attr:`daemon` property or the *daemon* constructor argument.
|
||||
|
||||
There is a "main thread" object; this corresponds to the initial thread of
|
||||
control in the Python program. It is not a daemon thread.
|
||||
|
@ -254,7 +254,8 @@ daemonic, and cannot be :meth:`join`\ ed. They are never deleted, since it is
|
|||
impossible to detect the termination of alien threads.
|
||||
|
||||
|
||||
.. class:: Thread(group=None, target=None, name=None, args=(), kwargs={})
|
||||
.. class:: Thread(group=None, target=None, name=None, args=(), kwargs={},
|
||||
verbose=None, *, daemon=None)
|
||||
|
||||
This constructor should always be called with keyword arguments. Arguments
|
||||
are:
|
||||
|
@ -273,10 +274,19 @@ impossible to detect the termination of alien threads.
|
|||
*kwargs* is a dictionary of keyword arguments for the target invocation.
|
||||
Defaults to ``{}``.
|
||||
|
||||
*verbose* is a flag used for debugging messages.
|
||||
|
||||
If not ``None``, *daemon* explicitly sets whether the thread is daemonic.
|
||||
If ``None`` (the default), the daemonic property is inherited from the
|
||||
current thread.
|
||||
|
||||
If the subclass overrides the constructor, it must make sure to invoke the
|
||||
base class constructor (``Thread.__init__()``) before doing anything else to
|
||||
the thread.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *daemon* argument.
|
||||
|
||||
.. method:: start()
|
||||
|
||||
Start the thread's activity.
|
||||
|
|
|
@ -91,12 +91,16 @@ class Process(object):
|
|||
'''
|
||||
_Popen = None
|
||||
|
||||
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
|
||||
def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
|
||||
*, daemon=None):
|
||||
assert group is None, 'group argument must be None for now'
|
||||
count = next(_current_process._counter)
|
||||
self._identity = _current_process._identity + (count,)
|
||||
self._authkey = _current_process._authkey
|
||||
self._daemonic = _current_process._daemonic
|
||||
if daemon is not None:
|
||||
self._daemonic = daemon
|
||||
else:
|
||||
self._daemonic = _current_process._daemonic
|
||||
self._tempdir = _current_process._tempdir
|
||||
self._parent_pid = os.getpid()
|
||||
self._popen = None
|
||||
|
|
|
@ -163,6 +163,18 @@ class _TestProcess(BaseTestCase):
|
|||
self.assertEqual(current.ident, os.getpid())
|
||||
self.assertEqual(current.exitcode, None)
|
||||
|
||||
def test_daemon_argument(self):
|
||||
if self.TYPE == "threads":
|
||||
return
|
||||
|
||||
# By default uses the current process's daemon flag.
|
||||
proc0 = self.Process(target=self._test)
|
||||
self.assertEquals(proc0.daemon, self.current_process().daemon)
|
||||
proc1 = self.Process(target=self._test, daemon=True)
|
||||
self.assertTrue(proc1.daemon)
|
||||
proc2 = self.Process(target=self._test, daemon=False)
|
||||
self.assertFalse(proc2.daemon)
|
||||
|
||||
@classmethod
|
||||
def _test(cls, q, *args, **kwds):
|
||||
current = cls.current_process()
|
||||
|
|
|
@ -427,6 +427,14 @@ class ThreadTests(BaseTestCase):
|
|||
t.daemon = True
|
||||
self.assertTrue('daemon' in repr(t))
|
||||
|
||||
def test_deamon_param(self):
|
||||
t = threading.Thread()
|
||||
self.assertFalse(t.daemon)
|
||||
t = threading.Thread(daemon=False)
|
||||
self.assertFalse(t.daemon)
|
||||
t = threading.Thread(daemon=True)
|
||||
self.assertTrue(t.daemon)
|
||||
|
||||
|
||||
class ThreadJoinOnShutdown(BaseTestCase):
|
||||
|
||||
|
|
|
@ -622,7 +622,7 @@ class Thread(_Verbose):
|
|||
#XXX __exc_clear = _sys.exc_clear
|
||||
|
||||
def __init__(self, group=None, target=None, name=None,
|
||||
args=(), kwargs=None, verbose=None):
|
||||
args=(), kwargs=None, verbose=None, *, daemon=None):
|
||||
assert group is None, "group argument must be None for now"
|
||||
_Verbose.__init__(self, verbose)
|
||||
if kwargs is None:
|
||||
|
@ -631,7 +631,10 @@ class Thread(_Verbose):
|
|||
self._name = str(name or _newname())
|
||||
self._args = args
|
||||
self._kwargs = kwargs
|
||||
self._daemonic = self._set_daemon()
|
||||
if daemon is not None:
|
||||
self._daemonic = daemon
|
||||
else:
|
||||
self._daemonic = current_thread().daemon
|
||||
self._ident = None
|
||||
self._started = Event()
|
||||
self._stopped = False
|
||||
|
@ -648,10 +651,6 @@ class Thread(_Verbose):
|
|||
self._block.__init__()
|
||||
self._started._reset_internal_locks()
|
||||
|
||||
def _set_daemon(self):
|
||||
# Overridden in _MainThread and _DummyThread
|
||||
return current_thread().daemon
|
||||
|
||||
def __repr__(self):
|
||||
assert self._initialized, "Thread.__init__() was not called"
|
||||
status = "initial"
|
||||
|
@ -948,15 +947,12 @@ class _Timer(Thread):
|
|||
class _MainThread(Thread):
|
||||
|
||||
def __init__(self):
|
||||
Thread.__init__(self, name="MainThread")
|
||||
Thread.__init__(self, name="MainThread", daemon=False)
|
||||
self._started.set()
|
||||
self._set_ident()
|
||||
with _active_limbo_lock:
|
||||
_active[self._ident] = self
|
||||
|
||||
def _set_daemon(self):
|
||||
return False
|
||||
|
||||
def _exitfunc(self):
|
||||
self._stop()
|
||||
t = _pickSomeNonDaemonThread()
|
||||
|
@ -988,7 +984,7 @@ def _pickSomeNonDaemonThread():
|
|||
class _DummyThread(Thread):
|
||||
|
||||
def __init__(self):
|
||||
Thread.__init__(self, name=_newname("Dummy-%d"))
|
||||
Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True)
|
||||
|
||||
# Thread._block consumes an OS-level locking primitive, which
|
||||
# can never be used by a _DummyThread. Since a _DummyThread
|
||||
|
@ -1000,9 +996,6 @@ class _DummyThread(Thread):
|
|||
with _active_limbo_lock:
|
||||
_active[self._ident] = self
|
||||
|
||||
def _set_daemon(self):
|
||||
return True
|
||||
|
||||
def join(self, timeout=None):
|
||||
assert False, "cannot join a dummy thread"
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #6064: Add a ``daemon`` keyword argument to the threading.Thread
|
||||
and multiprocessing.Process constructors in order to override the
|
||||
default behaviour of inheriting the daemonic property from the current
|
||||
thread/process.
|
||||
|
||||
- Issue #10956: Buffered I/O classes retry reading or writing after a signal
|
||||
has arrived and the handler returned successfully.
|
||||
|
||||
|
|
Loading…
Reference in New Issue