Add a bunch of comments to StoppableThread
This commit is contained in:
parent
19497ca229
commit
6bee825db7
@ -8,43 +8,83 @@
|
|||||||
import os
|
import os
|
||||||
import ctypes
|
import ctypes
|
||||||
import threading
|
import threading
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
|
|
||||||
__all__ = ('StoppableThread', 'JoinThread')
|
__all__ = ('StoppableThread', 'JoinThread')
|
||||||
|
|
||||||
class StoppableThread(threading.Thread):
|
class StoppableThread(threading.Thread):
|
||||||
'''
|
'''
|
||||||
StoppableThread - A thread that can be stopped by forcing an exception in the execution context.
|
StoppableThread - A thread that can be stopped by forcing an exception in the execution context.
|
||||||
|
|
||||||
|
This works both to interrupt code that is in C or in python code, at either the next call to a python function,
|
||||||
|
or the next line in python code.
|
||||||
|
|
||||||
|
It is recommended that if you call stop ( @see StoppableThread.stop ) that you use an exception that inherits BaseException, to ensure it likely isn't caught.
|
||||||
|
|
||||||
|
Also, beware unmarked exception handlers in your code. Code like this:
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
doSomething()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
will never be able to abort, because the exception you raise is immediately caught.
|
||||||
|
|
||||||
|
The exception is raised over and over, with a specifed delay (default 2.0 seconds)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
def _stopThread(self, exception):
|
def _stopThread(self, exception, raiseEvery=2.0):
|
||||||
|
'''
|
||||||
|
_stopThread - @see StoppableThread.stop
|
||||||
|
'''
|
||||||
if self.isAlive() is False:
|
if self.isAlive() is False:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self._stderr = open(os.devnull, 'w')
|
self._stderr = open(os.devnull, 'w')
|
||||||
joinThread = JoinThread(self, exception)
|
|
||||||
|
# Create "joining" thread which will raise the provided exception
|
||||||
|
# on a repeat, until the thread stops.
|
||||||
|
joinThread = JoinThread(self, exception, repeatEvery=raiseEvery)
|
||||||
|
|
||||||
|
# Try to prevent spurrious prints
|
||||||
joinThread._stderr = self._stderr
|
joinThread._stderr = self._stderr
|
||||||
joinThread.start()
|
joinThread.start()
|
||||||
joinThread._stderr = self._stderr
|
joinThread._stderr = self._stderr
|
||||||
|
|
||||||
def stop(self, exception):
|
def stop(self, exception, raiseEvery=2.0):
|
||||||
'''
|
'''
|
||||||
Stops the thread by raising a given exception.
|
Stops the thread by raising a given exception.
|
||||||
|
|
||||||
@param exception <Exception> - Exception to throw. Likely, you want to use something
|
@param exception <Exception> - Exception to throw. Likely, you want to use something
|
||||||
that inherits from BaseException (so except Exception as e: continue; isn't a problem)
|
that inherits from BaseException (so except Exception as e: continue; isn't a problem)
|
||||||
'''
|
'''
|
||||||
return self._stopThread(exception)
|
return self._stopThread(exception, raiseEvery)
|
||||||
|
|
||||||
|
|
||||||
class JoinThread(threading.Thread):
|
class JoinThread(threading.Thread):
|
||||||
'''
|
'''
|
||||||
JoinThread - The workhouse that stops the StoppableThread
|
JoinThread - The workhouse that stops the StoppableThread.
|
||||||
|
|
||||||
|
Takes an exception, and upon being started immediately raises that exception in the current context
|
||||||
|
of the thread's execution (so next line of python gets it, or next call to a python api function in C code ).
|
||||||
|
|
||||||
|
@see StoppableThread for more details
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, otherThread, exception, repeatEvery=2.0):
|
def __init__(self, otherThread, exception, repeatEvery=2.0):
|
||||||
|
'''
|
||||||
|
__init__ - Create a JoinThread (don't forget to call .start() ! )
|
||||||
|
|
||||||
|
@param otherThread <threading.Thread> - A thread
|
||||||
|
|
||||||
|
@param exception <BaseException> - An exception. Should be a BaseException, to prevent "catch Exception as e: continue" type code
|
||||||
|
from never being terminated. If such code is unavoidable, you can try setting #repeatEvery to a very low number, like .00001,
|
||||||
|
and it will hopefully raise within the context of the catch, and be able to break free.
|
||||||
|
|
||||||
|
@param repeatEvery <float> Default 2.0 - After starting, the given exception is immediately raised. Then, every #repeatEvery seconds,
|
||||||
|
it is raised again, until the thread terminates.
|
||||||
|
'''
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.otherThread = otherThread
|
self.otherThread = otherThread
|
||||||
self.exception = exception
|
self.exception = exception
|
||||||
@ -52,6 +92,9 @@ class JoinThread(threading.Thread):
|
|||||||
self.daemon = True
|
self.daemon = True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
'''
|
||||||
|
run - The thread main. Will attempt to stop and join the attached thread.
|
||||||
|
'''
|
||||||
|
|
||||||
# Try to silence default exception printing.
|
# Try to silence default exception printing.
|
||||||
self.otherThread._Thread__stderr = self._stderr
|
self.otherThread._Thread__stderr = self._stderr
|
||||||
@ -69,4 +112,4 @@ class JoinThread(threading.Thread):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# vim: set ts=4 sw=4 expandtab :
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user