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

Skip to content

Commit c57a84f

Browse files
committed
Merged revisions 73694,73708,73738 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r73694 | jesse.noller | 2009-06-29 14:24:26 -0400 (Mon, 29 Jun 2009) | 1 line Issue 5740: multiprocessing.connection.* authkey fixes ........ r73708 | jesse.noller | 2009-06-30 13:11:52 -0400 (Tue, 30 Jun 2009) | 1 line Resolves issues 5155, 5313, 5331 - bad file descriptor error with processes in processes ........ r73738 | r.david.murray | 2009-06-30 22:49:10 -0400 (Tue, 30 Jun 2009) | 2 lines Make punctuation prettier and break up run-on sentence. ........
1 parent 260484d commit c57a84f

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

Doc/library/multiprocessing.rst

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,7 +1715,7 @@ authentication* using the :mod:`hmac` module.
17151715
generally be omitted since it can usually be inferred from the format of
17161716
*address*. (See :ref:`multiprocessing-address-formats`)
17171717

1718-
If *authentication* is ``True`` or *authkey* is a string then digest
1718+
If *authenticate* is ``True`` or *authkey* is a string then digest
17191719
authentication is used. The key used for authentication will be either
17201720
*authkey* or ``current_process().authkey)`` if *authkey* is ``None``.
17211721
If authentication fails then :exc:`AuthenticationError` is raised. See
@@ -1757,7 +1757,7 @@ authentication* using the :mod:`hmac` module.
17571757

17581758
If *authkey* is ``None`` and *authenticate* is ``True`` then
17591759
``current_process().authkey`` is used as the authentication key. If
1760-
*authkey* is ``None`` and *authentication* is ``False`` then no
1760+
*authkey* is ``None`` and *authenticate* is ``False`` then no
17611761
authentication is done. If authentication fails then
17621762
:exc:`AuthenticationError` is raised. See :ref:`multiprocessing-auth-keys`.
17631763

@@ -2099,6 +2099,38 @@ Explicitly pass resources to child processes
20992099
for i in range(10):
21002100
Process(target=f, args=(lock,)).start()
21012101

2102+
Beware replacing sys.stdin with a "file like object"
2103+
2104+
:mod:`multiprocessing` originally unconditionally called::
2105+
2106+
os.close(sys.stdin.fileno())
2107+
2108+
in the :meth:`multiprocessing.Process._bootstrap` method --- this resulted
2109+
in issues with processes-in-processes. This has been changed to::
2110+
2111+
sys.stdin.close()
2112+
sys.stdin = open(os.devnull)
2113+
2114+
Which solves the fundamental issue of processes colliding with each other
2115+
resulting in a bad file descriptor error, but introduces a potential danger
2116+
to applications which replace :func:`sys.stdin` with a "file-like object"
2117+
with output buffering. This danger is that if multiple processes call
2118+
:func:`close()` on this file-like object, it could result in the same
2119+
data being flushed to the object multiple times, resulting in corruption.
2120+
2121+
If you write a file-like object and implement your own caching, you can
2122+
make it fork-safe by storing the pid whenever you append to the cache,
2123+
and discarding the cache when the pid changes. For example::
2124+
2125+
@property
2126+
def cache(self):
2127+
pid = os.getpid()
2128+
if pid != self._pid:
2129+
self._pid = pid
2130+
self._cache = []
2131+
return self._cache
2132+
2133+
For more information, see :issue:`5155`, :issue:`5313` and :issue:`5331`
21022134

21032135
Windows
21042136
~~~~~~~

Lib/multiprocessing/process.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ def _bootstrap(self):
221221
self._counter = itertools.count(1)
222222
if sys.stdin is not None:
223223
try:
224-
os.close(sys.stdin.fileno())
224+
sys.stdin.close()
225+
sys.stdin = open(os.devnull)
225226
except (OSError, ValueError):
226227
pass
227228
_current_process = self

Lib/test/test_multiprocessing.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import threading
99
import queue as pyqueue
1010
import time
11+
import io
1112
import sys
1213
import os
1314
import gc
@@ -1868,7 +1869,74 @@ def test_pool_initializer(self):
18681869
p.join()
18691870
self.assertEqual(self.ns.test, 1)
18701871

1871-
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers]
1872+
#
1873+
# Issue 5155, 5313, 5331: Test process in processes
1874+
# Verifies os.close(sys.stdin.fileno) vs. sys.stdin.close() behavior
1875+
#
1876+
1877+
def _ThisSubProcess(q):
1878+
try:
1879+
item = q.get(block=False)
1880+
except pyqueue.Empty:
1881+
pass
1882+
1883+
def _TestProcess(q):
1884+
queue = multiprocessing.Queue()
1885+
subProc = multiprocessing.Process(target=_ThisSubProcess, args=(queue,))
1886+
subProc.start()
1887+
subProc.join()
1888+
1889+
def _afunc(x):
1890+
return x*x
1891+
1892+
def pool_in_process():
1893+
pool = multiprocessing.Pool(processes=4)
1894+
x = pool.map(_afunc, [1, 2, 3, 4, 5, 6, 7])
1895+
1896+
class _file_like(object):
1897+
def __init__(self, delegate):
1898+
self._delegate = delegate
1899+
self._pid = None
1900+
1901+
@property
1902+
def cache(self):
1903+
pid = os.getpid()
1904+
# There are no race conditions since fork keeps only the running thread
1905+
if pid != self._pid:
1906+
self._pid = pid
1907+
self._cache = []
1908+
return self._cache
1909+
1910+
def write(self, data):
1911+
self.cache.append(data)
1912+
1913+
def flush(self):
1914+
self._delegate.write(''.join(self.cache))
1915+
self._cache = []
1916+
1917+
class TestStdinBadfiledescriptor(unittest.TestCase):
1918+
1919+
def test_queue_in_process(self):
1920+
queue = multiprocessing.Queue()
1921+
proc = multiprocessing.Process(target=_TestProcess, args=(queue,))
1922+
proc.start()
1923+
proc.join()
1924+
1925+
def test_pool_in_process(self):
1926+
p = multiprocessing.Process(target=pool_in_process)
1927+
p.start()
1928+
p.join()
1929+
1930+
def test_flushing(self):
1931+
sio = io.StringIO()
1932+
flike = _file_like(sio)
1933+
flike.write('foo')
1934+
proc = multiprocessing.Process(target=lambda: flike.flush())
1935+
flike.flush()
1936+
assert sio.getvalue() == 'foo'
1937+
1938+
testcases_other = [OtherTest, TestInvalidHandle, TestInitializers,
1939+
TestStdinBadfiledescriptor]
18721940

18731941
#
18741942
#

Misc/ACKS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ Des Barry
4646
Ulf Bartelt
4747
Nick Bastin
4848
Jeff Bauer
49+
Mike Bayer
4950
Michael R Bax
5051
Anthony Baxter
5152
Samuel L. Bayer
@@ -185,6 +186,7 @@ Cesar Douady
185186
Dean Draayer
186187
John DuBois
187188
Paul Dubois
189+
Graham Dumpleton
188190
Quinn Dunkan
189191
Robin Dunn
190192
Luke Dunstan
@@ -558,6 +560,7 @@ Steven Pemberton
558560
Santiago Peresón
559561
Mark Perrego
560562
Trevor Perrin
563+
Gabriel de Perthuis
561564
Tim Peters
562565
Benjamin Peterson
563566
Chris Petrilli

0 commit comments

Comments
 (0)