diff -r 377bd6e0f61c Doc/library/multiprocessing.rst --- a/Doc/library/multiprocessing.rst Mon Sep 09 22:40:13 2013 -0700 +++ b/Doc/library/multiprocessing.rst Tue Sep 10 17:38:17 2013 +0200 @@ -162,8 +162,13 @@ p.start() p.join() -:func:`set_start_method` should not be used more than once in the -program. +:func:`set_start_method` should not be used more than once in the program, +and will raise an exception when called a second time. +To check whether the start method has already been set, +call :func:`get_start_method` first:: + + if mp.get_start_method is not None: + mp.set_start_method('forkserver') @@ -861,9 +866,13 @@ .. function:: get_start_method() - Return the current start method. This can be ``'fork'``, - ``'spawn'`` or ``'forkserver'``. ``'fork'`` is the default on - Unix, while ``'spawn'`` is the default on Windows. + Return the current start method. This can be ``'fork'``, ``'spawn'``, + ``'forkserver'`` or ``None``. ``None`` means the start method has not + yet been set and the default will be used when the program attempts + multiprocessing. + + ``'fork'`` is the default on Unix, while ``'spawn'`` is the + default on Windows. .. versionadded:: 3.4 @@ -883,7 +892,8 @@ .. function:: set_start_method(method) Set the method which should be used to start child processes. - *method* can be ``'fork'``, ``'spawn'`` or ``'forkserver'``. + *method* can be ``'fork'``, ``'spawn'``, ``'forkserver'`` or ``None`` + (for the OS-dependent default; see :func:`get_start_method`). Note that this should be called at most once, and it should be protected inside the ``if __name__ == '__main__'`` clause of the diff -r 377bd6e0f61c Lib/multiprocessing/__init__.py --- a/Lib/multiprocessing/__init__.py Mon Sep 09 22:40:13 2013 -0700 +++ b/Lib/multiprocessing/__init__.py Tue Sep 10 17:38:17 2013 +0200 @@ -255,14 +255,18 @@ Set method for starting processes: 'fork', 'spawn' or 'forkserver'. ''' from .popen import set_start_method + current = get_start_method() + if current is not None: + raise RuntimeError('start method already set to %r' % current) set_start_method(method) def get_start_method(): ''' Get method for starting processes: 'fork', 'spawn' or 'forkserver'. + Returns None if the start method has not yet been set. ''' from .popen import get_start_method - return get_start_method() + return get_start_method(set_if_needed=False) def get_all_start_methods(): ''' diff -r 377bd6e0f61c Lib/multiprocessing/popen.py --- a/Lib/multiprocessing/popen.py Mon Sep 09 22:40:13 2013 -0700 +++ b/Lib/multiprocessing/popen.py Tue Sep 10 17:38:17 2013 +0200 @@ -34,12 +34,19 @@ set_start_method() return _Popen(process_obj) -def get_start_method(): +def get_start_method(set_if_needed=True): if _Popen is None: - set_start_method() + if set_if_needed: + set_start_method() + else: + return None return _Popen.method def set_start_method(meth=None, *, start_helpers=True): + ''' + Unsafe version of multiprocessing.set_start_method: does not check + whether the start method has already been set. + ''' global _Popen try: modname = _method_to_module[meth] diff -r 377bd6e0f61c Lib/test/_test_multiprocessing.py --- a/Lib/test/_test_multiprocessing.py Mon Sep 09 22:40:13 2013 -0700 +++ b/Lib/test/_test_multiprocessing.py Tue Sep 10 17:38:17 2013 +0200 @@ -3550,13 +3550,15 @@ try: for method in ('fork', 'spawn', 'forkserver'): try: - multiprocessing.set_start_method(method) + multiprocessing.popen.set_start_method(method) except ValueError: continue self.assertEqual(multiprocessing.get_start_method(), method) + self.assertRaises(RuntimeError, + multiprocessing.set_start_method, method) count += 1 finally: - multiprocessing.set_start_method(old_method) + multiprocessing.popen.set_start_method(old_method) self.assertGreaterEqual(count, 1) def test_get_all(self): @@ -3743,7 +3745,7 @@ dangling[1] = threading._dangling.copy() old_start_method[0] = multiprocessing.get_start_method() try: - multiprocessing.set_start_method(start_method) + multiprocessing.popen.set_start_method(start_method) except ValueError: raise unittest.SkipTest(start_method + ' start method not supported') @@ -3759,7 +3761,7 @@ multiprocessing.get_logger().setLevel(LOG_LEVEL) def tearDownModule(): - multiprocessing.set_start_method(old_start_method[0]) + multiprocessing.popen.set_start_method(old_start_method[0]) # pause a bit so we don't get warning about dangling threads/processes time.sleep(0.5) multiprocessing.process._cleanup()