summaryrefslogtreecommitdiff
path: root/Lib/multiprocessing/process.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/multiprocessing/process.py')
-rw-r--r--Lib/multiprocessing/process.py35
1 files changed, 35 insertions, 0 deletions
diff --git a/Lib/multiprocessing/process.py b/Lib/multiprocessing/process.py
index 37365f2e42..70bb50d999 100644
--- a/Lib/multiprocessing/process.py
+++ b/Lib/multiprocessing/process.py
@@ -76,6 +76,7 @@ class BaseProcess(object):
self._config = _current_process._config.copy()
self._parent_pid = os.getpid()
self._popen = None
+ self._closed = False
self._target = target
self._args = tuple(args)
self._kwargs = dict(kwargs)
@@ -85,6 +86,10 @@ class BaseProcess(object):
self.daemon = daemon
_dangling.add(self)
+ def _check_closed(self):
+ if self._closed:
+ raise ValueError("process object is closed")
+
def run(self):
'''
Method to be run in sub-process; can be overridden in sub-class
@@ -96,6 +101,7 @@ class BaseProcess(object):
'''
Start child process
'''
+ self._check_closed()
assert self._popen is None, 'cannot start a process twice'
assert self._parent_pid == os.getpid(), \
'can only start a process object created by current process'
@@ -110,12 +116,14 @@ class BaseProcess(object):
'''
Terminate process; sends SIGTERM signal or uses TerminateProcess()
'''
+ self._check_closed()
self._popen.terminate()
def join(self, timeout=None):
'''
Wait until child process terminates
'''
+ self._check_closed()
assert self._parent_pid == os.getpid(), 'can only join a child process'
assert self._popen is not None, 'can only join a started process'
res = self._popen.wait(timeout)
@@ -126,6 +134,7 @@ class BaseProcess(object):
'''
Return whether process is alive
'''
+ self._check_closed()
if self is _current_process:
return True
assert self._parent_pid == os.getpid(), 'can only test a child process'
@@ -134,6 +143,23 @@ class BaseProcess(object):
self._popen.poll()
return self._popen.returncode is None
+ def close(self):
+ '''
+ Close the Process object.
+
+ This method releases resources held by the Process object. It is
+ an error to call this method if the child process is still running.
+ '''
+ if self._popen is not None:
+ if self._popen.poll() is None:
+ raise ValueError("Cannot close a process while it is still running. "
+ "You should first call join() or terminate().")
+ self._popen.close()
+ self._popen = None
+ del self._sentinel
+ _children.discard(self)
+ self._closed = True
+
@property
def name(self):
return self._name
@@ -174,6 +200,7 @@ class BaseProcess(object):
'''
Return exit code of process or `None` if it has yet to stop
'''
+ self._check_closed()
if self._popen is None:
return self._popen
return self._popen.poll()
@@ -183,6 +210,7 @@ class BaseProcess(object):
'''
Return identifier (PID) of process or `None` if it has yet to start
'''
+ self._check_closed()
if self is _current_process:
return os.getpid()
else:
@@ -196,6 +224,7 @@ class BaseProcess(object):
Return a file descriptor (Unix) or handle (Windows) suitable for
waiting for process termination.
'''
+ self._check_closed()
try:
return self._sentinel
except AttributeError:
@@ -204,6 +233,8 @@ class BaseProcess(object):
def __repr__(self):
if self is _current_process:
status = 'started'
+ elif self._closed:
+ status = 'closed'
elif self._parent_pid != os.getpid():
status = 'unknown'
elif self._popen is None:
@@ -295,6 +326,7 @@ class _MainProcess(BaseProcess):
self._name = 'MainProcess'
self._parent_pid = None
self._popen = None
+ self._closed = False
self._config = {'authkey': AuthenticationString(os.urandom(32)),
'semprefix': '/mp'}
# Note that some versions of FreeBSD only allow named
@@ -307,6 +339,9 @@ class _MainProcess(BaseProcess):
# Everything in self._config will be inherited by descendant
# processes.
+ def close(self):
+ pass
+
_current_process = _MainProcess()
_process_counter = itertools.count(1)