#!/bin/env python
# -*- coding: utf-8 -*-
#filename:
import threading, signal
is_exit = False
def doStress(i, cc):
global is_exit
idx = i
while not is_exit:
if (idx < 10000000):
print "thread[%d]: idx=%d"%(i, idx)
idx = idx + cc
else:
break
print "thread[%d] complete."%i
def handler(signum, frame):
global is_exit
is_exit = True
print "receive a signal %d, is_exit = %d"%(signum, is_exit)
if __name__ == "__main__":
(, handler)
(, handler)
cc = 5
for i in range(cc):
t = (target=doStress, args=(i,cc))
()
The above is a simulation program that doesn't actually send requests to the service, but instead substitutes an integer printed every concurrent number (cc's) by each thread up to 10 million. Obviously, the process will exit normally when all threads have completed their tasks. But what if we want to exit in the middle of the process (imagine a stress test program that has found a problem in the middle and needs to be stopped)? Of course you can use ps to find the process number, and then kill -9 kill, but this is too cumbersome, capture Ctrl + C is the most natural idea. The above example program has captured this signal and modified the global variable is_exit, which is detected in the thread and exits in time.
But in fact this program doesn't WORK, when you press Ctrl+C, the program runs as usual and doesn't respond. After searching the internet, I realized that python's sub-threads can't respond to any interrupts if they are not daemons. However, the main thread will exit after being set as a daemon, and then the whole process will exit soon, so you also need to detect the status of each sub-thread in the main thread, until all the sub-threads exit before exiting yourself, so the code after line 29 of the above example can be modified to:
threads=[]
for i in range(cc):
t = (target=doStress, args=(i, cc))
(True)
(t)
()
for i in range(cc):
threads[i].join()
Retry, the problem is still not solved, the process is still not responding to Ctrl + C. This is because the join() function will also WAITING on a lock, so that the main thread can not capture the signal. So continue to modify, call the thread isAlive () function to determine whether the thread is complete:
while 1:
alive = False
for i in range(cc):
alive = alive or threads[i].isAlive()
if not alive:
break
With this modification, the program works exactly as expected: you can print all the numbers that each thread is supposed to print without any problems, and you can also terminate the whole process with Ctrl+C halfway through. The complete code is as follows:
#!/bin/env python
# -*- coding: utf-8 -*-
#filename:
import threading, signal
is_exit = False
def doStress(i, cc):
global is_exit
idx = i
while not is_exit:
if (idx < 10000000):
print "thread[%d]: idx=%d"%(i, idx)
idx = idx + cc
else:
break
if is_exit:
print "receive a signal to exit, thread[%d] stop."%i
else:
print "thread[%d] complete."%i
def handler(signum, frame):
global is_exit
is_exit = True
print "receive a signal %d, is_exit = %d"%(signum, is_exit)
if __name__ == "__main__":
(, handler)
(, handler)
cc = 5
threads = []
for i in range(cc):
t = (target=doStress, args=(i,cc))
(True)
(t)
()
while 1:
alive = False
for i in range(cc):
alive = alive or threads[i].isAlive()
if not alive:
break
1. Set all child threads to Daemon;
2. Use the isAlive() function to determine whether all child threads are complete, rather than waiting for completion in the main thread with the join() function;
3. Write a function that responds to the Ctrl+C signal and modifies the global variables so that each sub-thread can detect it and exit normally.