Shrikanth Kalluraya
Shrikanth Kalluraya

Reputation: 1119

Stop a main thread from child thread

I am writing a python program, In main function I am starting a thread which runs continuously. After starting the the thread the main function enters a while loop where it takes user input continuously. If there is a exception in child thread I want to end the main function also. What is the best way to do that?

Thanks in advance

Upvotes: 4

Views: 4897

Answers (2)

shx2
shx2

Reputation: 64318

Having a thread "controlling" its parent is not a good practice. It makes more sense for the main thread to manage/monitor/control the threads it starts.

So my suggestion is that your main thread starts 2 threads: the one you already have, which at some point finishes/raises an exception, and one reading user input. The main thread now waits (joins) for the former to finish, and exits once done.

from threading import Thread
import time

class ThreadA(Thread):
    def run(self):
        print 'T1: sleeping...'
        time.sleep(4)
        print 'T1: raising...'
        raise RuntimeError('bye')

class ThreadB(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.daemon = True
    def run(self):
        while True:
            x = raw_input('T2: enter some input: ')
            print 'GOT:', x

t1 = ThreadA()
t2 = ThreadB()
t1.start()
t2.start()
t1.join()  # wait for t1 to finish/raise
print 'done'

Since ThreadB is daemonic, we don't have to explicitly make it stop, nor to join it. When the main thread exits, it exits as well.

IMO, there's no need to resort to low-level stuff like signals. This solution doesn't even require using try-except (though you may decide you want a try-except in ThreadA, to make it exit cleanly).

Upvotes: 7

Srikar Appalaraju
Srikar Appalaraju

Reputation: 73608

Python gives you access to this system call via the signal module, so you can register a signal handler for SIGINT and do whatever you like. The default SIGINT handler, by the way, simply raises a KeyboardInterrupt exception, so if you don't want to use signals you can put your entire program in a try/except structure and get more or less the same effect. Since you want to stop main thread on any crash in child thread simply put the whole while loop in except Exception: try-except block.

This should work but some background information - Python's signal module documentation explicitly states that when multiple threads are running, only the main thread (i.e. the thread that was created when your process started) will receive signals (for you it should not matter since you want the signal in main thread). So the signal handler will execute only in one thread and not in all of them. In order to get all threads to stop in response to a signal, you need the main thread's signal handler to communicate the stop message to the other child threads. This can be done in different ways, the simplest being by having the main thread flip the value of a boolean variable that all child threads hold a reference too. This is just to capture a scenario where one of your child thread crashes and a signal is sent to the main thread to gracefully shut-down, using the above method you can switch off child threads without abruptly terminating them.

Upvotes: 4

Related Questions