DataGreed
DataGreed

Reputation: 13899

Stopping all threads working on queue with a Keyboard interrupt

I have the following code:

from Queue import Queue
from threading import Thread

num_worker_threads = 10

# some items to work on
def source():
    return xrange(400)

# the actual work to be done
def do_work(smth):
    # some really heavy task here
    print("{}\r".format(smth))

# worker that retrieves data from queue and executes work
def worker():
    while True:
        item = q.get()
        do_work(item)
        q.task_done()

q = Queue()
for i in range(num_worker_threads):
     t = Thread(target=worker)  #use args to pass args
     t.daemon = True
     t.start()

# queues items to work on
for item in source():
    q.put(item)

# blocks until work is finished
q.join()  

How do I stop all threads when I press Ctrl+C? When I do it, the program execution continues.

I've seen similar questions on StackOverflow, but they don't use join().

I am confused on what exactly I should wrap with try..except here and how should I stop the threads?

Upvotes: 0

Views: 683

Answers (1)

fendall
fendall

Reputation: 524

By calling q.join(), you are just waiting for the threads to end. You need to be able to tell a thread (from the main thread) to stop its execution.

A good way to do this is to change the implementation of your worker. Instead of being a function, it should be a class that inherits from threading.Thread.

You can give the Worker an attribute that can be changed from the main thread that tells it to stop doing work.

import threading
class Worker(threading.Thread):
    def __init__(self, queue):
        self.keep_doing_work = True
        self.q = queue
        threading.Thread.__init__(self)

    def run(self):
        while self.keep_doing_work is True:
            item = self.q.get()
            self.do_work(item)
            q.task_done()

    def do_work(smth):
        print("{}\r".format(smth))

num_worker_threads = 10

my_threads = []

try:
    for i in range(num_worker_threads):
        t = Worker()
        my_threads.append(t)
        t.start()

except KeyboardInterrupt:
    for t in my_threads:
        t.keep_doing_work = False   

Upvotes: 1

Related Questions