Add a bunch of comments to StoppableThread

This commit is contained in:
Tim Savannah 2017-06-04 04:41:44 -04:00
parent 19497ca229
commit 6bee825db7

View File

@ -8,43 +8,83 @@
import os
import ctypes
import threading
import time
import sys
__all__ = ('StoppableThread', 'JoinThread')
class StoppableThread(threading.Thread):
'''
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:
return True
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.start()
joinThread._stderr = self._stderr
def stop(self, exception):
def stop(self, exception, raiseEvery=2.0):
'''
Stops the thread by raising a given exception.
@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)
'''
return self._stopThread(exception)
return self._stopThread(exception, raiseEvery)
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):
'''
__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)
self.otherThread = otherThread
self.exception = exception
@ -52,6 +92,9 @@ class JoinThread(threading.Thread):
self.daemon = True
def run(self):
'''
run - The thread main. Will attempt to stop and join the attached thread.
'''
# Try to silence default exception printing.
self.otherThread._Thread__stderr = self._stderr
@ -69,4 +112,4 @@ class JoinThread(threading.Thread):
except:
pass
# vim: set ts=4 sw=4 expandtab :