I'm looking for a way to let the threads finish their work and not take a new job if CTRL-C is raised. Theorical code:
import threading
from Queue import Queue
q = Queue(maxsize=0)
def work(q):
print (line)
for line in file_of_100_line:
q.put(line)
nbThreads = 2
for i in range(nbThreads):
t = threading.Thread(target=work, args=(q))
t.setDaemon(True)
t.start()
Let the workers print the line if keyboard exception is raised (CTRL-C), and when all workers are done with their current task, quit.
The following should do what you want:
import signal
import threading
from time import sleep
keep_running = True
def signal_handler(signal, frame):
global keep_running
keep_running = False
print("Received SIGINT\n")
signal.signal(signal.SIGINT,signal_handler)
def work():
while keep_running:
sleep(2)
print("Worker finished\n")
nbThreads = 2
threads = []
for i in range(nbThreads):
t = threading.Thread(target=work)
t.setDaemon(True)
t.start()
threads.append(t)
while any([t.isAlive() for t in threads]):
sleep(0.1)
Letting this program run yields
Received SIGINT
Worker finished
Worker finished
Explanation: When CTRL-C is pressed the program receives a signal.SIGINT
which causes the registered handler signal_handler
to be called setting the global variable keep_running
to False
. Meanwhile the main thread waits for all spawned threads to die. Thus these threads can finish whatever they were doing (in this case sleep
-ing) before the main thread terminates.
Note: On Linux waiting for a signal could be achieved by calling signal.pause()
(replacing the sleep(0.1)
). On Windows this is not possible because this function does not exist. Therefore the above should be less platform-dependant.