diff options
author | Antoine Pitrou <pitrou@free.fr> | 2017-06-24 19:22:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-24 19:22:23 +0200 |
commit | 13e96cc596d158b98996db3fa291086ea4afecd9 (patch) | |
tree | e5d5abb7f5364b484ca4396ff99986ccac16ed0c /Lib/multiprocessing/process.py | |
parent | 0ee32c148119031e19c79359f5c4789ee69fa355 (diff) | |
download | cpython-git-13e96cc596d158b98996db3fa291086ea4afecd9.tar.gz |
Fix bpo-30596: Add close() method to multiprocessing.Process (#2010)
* Fix bpo-30596: Add close() method to multiprocessing.Process
* Raise ValueError if close() is called before the Process is finished running
* Add docs
* Add NEWS blurb
Diffstat (limited to 'Lib/multiprocessing/process.py')
-rw-r--r-- | Lib/multiprocessing/process.py | 35 |
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) |