Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminate a multi-thread python program

How to make a multi-thread python program response to Ctrl+C key event?

Edit: The code is like this:

import threading current = 0  class MyThread(threading.Thread):     def __init__(self, total):         threading.Thread.__init__(self)         self.total = total      def stop(self):         self._Thread__stop()      def run(self):         global current         while current<self.total:             lock = threading.Lock()             lock.acquire()             current+=1             lock.release()             print current  if __name__=='__main__':      threads = []     thread_count = 10     total = 10000     for i in range(0, thread_count):         t = MyThread(total)         t.setDaemon(True)         threads.append(t)     for i in range(0, thread_count):         threads[i].start() 

I tried to remove join() on all threads but it still doesn't work. Is it because the lock segment inside each thread's run() procedure?

Edit: The above code is supposed to work but it always interrupted when current variable was in 5,000-6,000 range and through out the errors as below

Exception in thread Thread-4 (most likely raised during interpreter shutdown): Traceback (most recent call last):   File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner   File "test.py", line 20, in run <type 'exceptions.TypeError'>: unsupported operand type(s) for +=: 'NoneType' and 'int' Exception in thread Thread-2 (most likely raised during interpreter shutdown): Traceback (most recent call last):   File "/usr/lib/python2.5/threading.py", line 486, in __bootstrap_inner   File "test.py", line 22, in run 
like image 511
jack Avatar asked Oct 28 '09 03:10

jack


People also ask

How do you start and stop a thread in Python?

Event can be checked via the is_set() function. The main thread, or another thread, can then set the event in order to stop the new thread from running. The event can be set or made True via the set() function. Now that we know how to stop a Python thread, let's look at some worked examples.

How do you exit a thread?

Thread , the function will be run() ). To end the thread, just return from that function. According to this, you can also call thread. exit() , which will throw an exception that will end the thread silently.

How do you stop a thread from looping in Python?

Threaded stoppable function. Instead of subclassing threading. Thread , one can modify the function to allow stopping by a flag. We need an object, accessible to running function, to which we set the flag to stop running.


2 Answers

Make every thread except the main one a daemon (t.daemon = True in 2.6 or better, t.setDaemon(True) in 2.6 or less, for every thread object t before you start it). That way, when the main thread receives the KeyboardInterrupt, if it doesn't catch it or catches it but decided to terminate anyway, the whole process will terminate. See the docs.

edit: having just seen the OP's code (not originally posted) and the claim that "it doesn't work", it appears I have to add...:

Of course, if you want your main thread to stay responsive (e.g. to control-C), don't mire it into blocking calls, such as joining another thread -- especially not totally useless blocking calls, such as joining daemon threads. For example, just change the final loop in the main thread from the current (utterless and damaging):

for i in range(0, thread_count):     threads[i].join() 

to something more sensible like:

while threading.active_count() > 0:     time.sleep(0.1) 

if your main has nothing better to do than either for all threads to terminate on their own, or for a control-C (or other signal) to be received.

Of course, there are many other usable patterns if you'd rather have your threads not terminate abruptly (as daemonic threads may) -- unless they, too, are mired forever in unconditionally-blocking calls, deadlocks, and the like;-).

like image 185
Alex Martelli Avatar answered Sep 22 '22 19:09

Alex Martelli


There're two main ways, one clean and one easy.

The clean way is to catch KeyboardInterrupt in your main thread, and set a flag your background threads can check so they know to exit; here's a simple/slightly-messy version using a global:

exitapp = False if __name__ == '__main__':     try:         main()     except KeyboardInterrupt:         exitapp = True         raise  def threadCode(...):     while not exitapp:         # do work here, watch for exitapp to be True 

The messy but easy way is to catch KeyboardInterrupt and call os._exit(), which terminates all threads immediately.

like image 44
Walter Mundt Avatar answered Sep 24 '22 19:09

Walter Mundt