Reputation: 8360
I wrote a small threading example in python. I am facing problem that when there's an exception inside a thread, that thread keeps on running and it won't exit. I have following code:
class Producer (threading.Thread):
def __init__(self, threadId):
threading.Thread.__init__(self)
self.threadId = threadId
self.killReceived = False
def produce(self):
while 1:
if self.killReceived == True:
print self.threadId+"inside kill section"
return False
print "running"
time.sleep(1)
raise Exception('boo')
def run(self):
try:
self.produce()
except Exception as e:
ThreadManager.getInstance().shutdown(self.threadId)
def stop(self):
self.killReceived = True
class ThreadManager:
_instance = None
@staticmethod
def getInstance():
if ThreadManager._instance == None:
ThreadManager._instance = ThreadManager()
return ThreadManager._instance
def __init__(self):
''' some initializations '''
def shutdown(self, threadId):
while threading.active_count() > 1:
for thread in threading.enumerate():
if type(thread) != threading._MainThread: #never kill main thread directly
thread.stop()
#print thread.threadId+" is alive? "+str(thread.isAlive())
When I raise exception inside producer it gets caught and I fire shutdown method of ThreadManager, which in turn calls stop() method of all running threads except main thread. Consumer exits using this strategy but producer hangs. If I run isAlive
method I see that producer threads are still running, however it's run method is no longer running. Because it no longer print running
.As exception bubbles out of produce
method which is inside run(), so thread should automatically finish. But it doesn't. So where exactly is the producer? How can I make it stop when some exception occurs?
Upvotes: 1
Views: 2730
Reputation: 287835
ThreadManager's shutdown
is not properly synchronized; it basically is a while threading.active_count() > 1
loop that is never exited. If two or more threads end up in this method, they (and the program) will never exit.
Instead of continually calling random threads (which may not even be related to yours), simply keep an inventory of all started threads in ThreadManager, and call stop
of each of them once. Also, the code that actually calls stop should move into the ThreadManager, where it logically belongs.
Additionally, ThreadManager.getInstance
is not thread-safe; you may end up with multiple ThreadManagers as it stands. You should use a lock.
All in all, it looks like you're reimplementing a ThreadPoolExecutor
. Why don't you use that instead?
Upvotes: 2