There's no reason to let your threads die.
If they're actually crashing, your whole program will crash.
If they're just raising exceptions, you can just catch the exceptions.
If they're returning normally, you can just not do that.
You can even trivially wrap a thread function to restart itself on exception or return:
def threadwrap(threadfunc):
def wrapper():
while True:
try:
threadfunc()
except BaseException as e:
print('{!r}; restarting thread'.format(e))
else:
print('exited normally, bad thread; restarting')
return wrapper
thread_dict = {
'a': threading.Thread(target=wrapper(a), name='a'),
'b': threading.Thread(target=wrapper(b), name='b')
}
Problem solved.
You cannot restart a thread.
Most platforms have no way to do so.
And conceptually, it doesn't make any sense. When a thread finished, its stack is dead; its parent is flagged or signaled; once it's joined, its resources are destroyed (including kernel-level resources like its process table entry). The only way to restart it would be to create a whole new set of everything. Which you can already do by creating a new thread.
So, just do it. If you really don't want to handle the exceptions internally, just store the construction arguments and use them to start a new thread.
You can even create your own subclass that hangs onto them for you:
class RestartableThread(threading.Thread):
def __init__(self, *args, **kwargs):
self._args, self._kwargs = args, kwargs
super().__init__(*args, **kwargs)
def clone(self):
return RestartableThread(*args, **kwargs)
And now it's easy to "copy" the thread (with the semantics you wanted):
if not a_thread.is_alive():
a_thread = a_thread.clone()
Yes, threading.Thread
objects are not safe to copy
What would you expect to happen? At best, you'd get a different wrapper around the same OS-level thread object, so you'd fool Python into not noticing that you're trying to do the illegal, possibly segfault-inducing things it was trying to stop you from doing.