Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0bd4deb

Browse files
committed
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.
1 parent 4bc6857 commit 0bd4deb

7 files changed

Lines changed: 59 additions & 21 deletions

File tree

Doc/library/multiprocessing.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ The :mod:`multiprocessing` package mostly replicates the API of the
297297
:class:`Process` and exceptions
298298
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
299299

300-
.. class:: Process([group[, target[, name[, args[, kwargs]]]]])
300+
.. class:: Process([group[, target[, name[, args[, kwargs]]]]], *, daemon=None)
301301

302302
Process objects represent activity that is run in a separate process. The
303303
:class:`Process` class has equivalents of all the methods of
@@ -312,13 +312,19 @@ The :mod:`multiprocessing` package mostly replicates the API of the
312312
:sub:`1`,N\ :sub:`2`,...,N\ :sub:`k` is a sequence of integers whose length
313313
is determined by the *generation* of the process. *args* is the argument
314314
tuple for the target invocation. *kwargs* is a dictionary of keyword
315-
arguments for the target invocation. By default, no arguments are passed to
316-
*target*.
315+
arguments for the target invocation. If provided, the keyword-only *daemon* argument
316+
sets the process :attr:`daemon` flag to ``True`` or ``False``. If ``None``
317+
(the default), this flag will be inherited from the creating process.
318+
319+
By default, no arguments are passed to *target*.
317320

318321
If a subclass overrides the constructor, it must make sure it invokes the
319322
base class constructor (:meth:`Process.__init__`) before doing anything else
320323
to the process.
321324

325+
.. versionchanged:: 3.3
326+
Added the *daemon* argument.
327+
322328
.. method:: run()
323329

324330
Method representing the process's activity.

Doc/library/threading.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ changed through the :attr:`name` attribute.
241241
A thread can be flagged as a "daemon thread". The significance of this flag is
242242
that the entire Python program exits when only daemon threads are left. The
243243
initial value is inherited from the creating thread. The flag can be set
244-
through the :attr:`daemon` property.
244+
through the :attr:`daemon` property or the *daemon* constructor argument.
245245

246246
There is a "main thread" object; this corresponds to the initial thread of
247247
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
254254
impossible to detect the termination of alien threads.
255255

256256

257-
.. class:: Thread(group=None, target=None, name=None, args=(), kwargs={})
257+
.. class:: Thread(group=None, target=None, name=None, args=(), kwargs={},
258+
verbose=None, *, daemon=None)
258259
259260
This constructor should always be called with keyword arguments. Arguments
260261
are:
@@ -273,10 +274,19 @@ impossible to detect the termination of alien threads.
273274
*kwargs* is a dictionary of keyword arguments for the target invocation.
274275
Defaults to ``{}``.
275276

277+
*verbose* is a flag used for debugging messages.
278+
279+
If not ``None``, *daemon* explicitly sets whether the thread is daemonic.
280+
If ``None`` (the default), the daemonic property is inherited from the
281+
current thread.
282+
276283
If the subclass overrides the constructor, it must make sure to invoke the
277284
base class constructor (``Thread.__init__()``) before doing anything else to
278285
the thread.
279286

287+
.. versionchanged:: 3.3
288+
Added the *daemon* argument.
289+
280290
.. method:: start()
281291

282292
Start the thread's activity.

Lib/multiprocessing/process.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,16 @@ class Process(object):
9191
'''
9292
_Popen = None
9393

94-
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
94+
def __init__(self, group=None, target=None, name=None, args=(), kwargs={},
95+
*, daemon=None):
9596
assert group is None, 'group argument must be None for now'
9697
count = next(_current_process._counter)
9798
self._identity = _current_process._identity + (count,)
9899
self._authkey = _current_process._authkey
99-
self._daemonic = _current_process._daemonic
100+
if daemon is not None:
101+
self._daemonic = daemon
102+
else:
103+
self._daemonic = _current_process._daemonic
100104
self._tempdir = _current_process._tempdir
101105
self._parent_pid = os.getpid()
102106
self._popen = None

Lib/test/test_multiprocessing.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ def test_current(self):
163163
self.assertEqual(current.ident, os.getpid())
164164
self.assertEqual(current.exitcode, None)
165165

166+
def test_daemon_argument(self):
167+
if self.TYPE == "threads":
168+
return
169+
170+
# By default uses the current process's daemon flag.
171+
proc0 = self.Process(target=self._test)
172+
self.assertEquals(proc0.daemon, self.current_process().daemon)
173+
proc1 = self.Process(target=self._test, daemon=True)
174+
self.assertTrue(proc1.daemon)
175+
proc2 = self.Process(target=self._test, daemon=False)
176+
self.assertFalse(proc2.daemon)
177+
166178
@classmethod
167179
def _test(cls, q, *args, **kwds):
168180
current = cls.current_process()

Lib/test/test_threading.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ def test_repr_daemon(self):
427427
t.daemon = True
428428
self.assertTrue('daemon' in repr(t))
429429

430+
def test_deamon_param(self):
431+
t = threading.Thread()
432+
self.assertFalse(t.daemon)
433+
t = threading.Thread(daemon=False)
434+
self.assertFalse(t.daemon)
435+
t = threading.Thread(daemon=True)
436+
self.assertTrue(t.daemon)
437+
430438

431439
class ThreadJoinOnShutdown(BaseTestCase):
432440

Lib/threading.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ class Thread(_Verbose):
622622
#XXX __exc_clear = _sys.exc_clear
623623

624624
def __init__(self, group=None, target=None, name=None,
625-
args=(), kwargs=None, verbose=None):
625+
args=(), kwargs=None, verbose=None, *, daemon=None):
626626
assert group is None, "group argument must be None for now"
627627
_Verbose.__init__(self, verbose)
628628
if kwargs is None:
@@ -631,7 +631,10 @@ def __init__(self, group=None, target=None, name=None,
631631
self._name = str(name or _newname())
632632
self._args = args
633633
self._kwargs = kwargs
634-
self._daemonic = self._set_daemon()
634+
if daemon is not None:
635+
self._daemonic = daemon
636+
else:
637+
self._daemonic = current_thread().daemon
635638
self._ident = None
636639
self._started = Event()
637640
self._stopped = False
@@ -648,10 +651,6 @@ def _reset_internal_locks(self):
648651
self._block.__init__()
649652
self._started._reset_internal_locks()
650653

651-
def _set_daemon(self):
652-
# Overridden in _MainThread and _DummyThread
653-
return current_thread().daemon
654-
655654
def __repr__(self):
656655
assert self._initialized, "Thread.__init__() was not called"
657656
status = "initial"
@@ -948,15 +947,12 @@ def run(self):
948947
class _MainThread(Thread):
949948

950949
def __init__(self):
951-
Thread.__init__(self, name="MainThread")
950+
Thread.__init__(self, name="MainThread", daemon=False)
952951
self._started.set()
953952
self._set_ident()
954953
with _active_limbo_lock:
955954
_active[self._ident] = self
956955

957-
def _set_daemon(self):
958-
return False
959-
960956
def _exitfunc(self):
961957
self._stop()
962958
t = _pickSomeNonDaemonThread()
@@ -988,7 +984,7 @@ def _pickSomeNonDaemonThread():
988984
class _DummyThread(Thread):
989985

990986
def __init__(self):
991-
Thread.__init__(self, name=_newname("Dummy-%d"))
987+
Thread.__init__(self, name=_newname("Dummy-%d"), daemon=True)
992988

993989
# Thread._block consumes an OS-level locking primitive, which
994990
# can never be used by a _DummyThread. Since a _DummyThread
@@ -1000,9 +996,6 @@ def __init__(self):
1000996
with _active_limbo_lock:
1001997
_active[self._ident] = self
1002998

1003-
def _set_daemon(self):
1004-
return True
1005-
1006999
def join(self, timeout=None):
10071000
assert False, "cannot join a dummy thread"
10081001

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ Core and Builtins
3535
Library
3636
-------
3737

38+
- Issue #6064: Add a ``daemon`` keyword argument to the threading.Thread
39+
and multiprocessing.Process constructors in order to override the
40+
default behaviour of inheriting the daemonic property from the current
41+
thread/process.
42+
3843
- Issue #10956: Buffered I/O classes retry reading or writing after a signal
3944
has arrived and the handler returned successfully.
4045

0 commit comments

Comments
 (0)