0

I'm facing problem with the thread concept i.e I have a function which will create 10 threads to do task. If any key board interruption occurs, those created threads are still executing and i would like to stop those threads and revert back the changes.

The following code sinppet is the sample approach:

def store_to_db(self,keys_size,master_key,action_flag,key_status):
    for iteration in range(10):
        t = threading.Thread(target=self.store_worker, args=())
        t.start()
        threads.append(t)
    for t in threads:
        t.join()

def store_worker():
    print "DOING"
sireesha j
  • 703
  • 3
  • 9
  • 23

1 Answers1

0

The idea to make this work is:

  • you need a "thread pool" where threads are checking against if their do_run attribute is falsy.
  • you need a "sentinel thread" outside that pool which checks the thread status in the pool and adjusts the do_run attribute of the "thread pool" thread on demand.

Example code:

import threading
import random
import time
import msvcrt as ms


def main_logic():
    # take 10 worker threads
    threads = []
    for i in range(10):
        t = threading.Thread(target=lengthy_process_with_brake, args=(i,))
        # start and append
        t.start()
        threads.append(t)

    # start the thread which allows you to stop all threads defined above
    s = threading.Thread(target=sentinel, args=(threads,))
    s.start()

    # join worker threads
    for t in threads:
        t.join()


def sentinel(threads):
    # this one runs until threads defined in "threads" are running or keyboard is pressed
    while True:
        # number of threads are running
        running = [x for x in threads if x.isAlive()]

        # if kb is pressed
        if ms.kbhit():
            # tell threads to stop
            for t in running:
                t.do_run = False
        # if all threads stopped, exit the loop
        if not running:
            break

        # you don't want a high cpu load for nothing
        time.sleep(0.05)


def lengthy_process_with_brake(worker_id):
    # grab current thread
    t = threading.currentThread()

    # start msg
    print(f"{worker_id} STARTED")

    # exit condition
    zzz = random.random() * 20
    stop_time = time.time() + zzz

    # imagine an iteration here like "for item in items:"  
    while time.time() < stop_time:

        # the brake
        if not getattr(t, "do_run", True):
            print(f"{worker_id} IS ESCAPING")
            return

        # the task
        time.sleep(0.03)

    # exit msg
    print(f"{worker_id} DONE")

    # exit msg
    print(f"{worker_id} DONE")



main_logic()

This solution does not 'kill' threads, just tell them to stop iterating or whatever they do.

EDIT: I just noticed that "Keyboard exception" was in the title and not "any key". Keyboard Exception handling is a bit different, here is a good solution for that. The point is almost the same: you tell the thread to return if a condition is met.

Trapli
  • 1,517
  • 2
  • 13
  • 19