首页 > 解决方案 > How to stop child threads if keyboard exception occurs in python?

问题描述

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"

标签: multithreadingpython-2.7keyboardinterrupt

解决方案


使这项工作的想法是:

  • 您需要一个“线程池”,线程正在检查它们的do_run属性是否为假。
  • 您需要该池外的“哨兵线程”检查池中的线程状态并根据需要调整do_run“线程池”线程的属性。

示例代码:

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()

这个解决方案不会“杀死”线程,只是告诉他们停止迭代或他们所做的任何事情。

编辑:我刚刚注意到“键盘异常”在标题中,而不是“任何键”。键盘异常处理有点不同,这里有一个很好的解决方案。要点几乎相同:如果满足条件,则告诉线程返回。


推荐阅读