@ -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 )