Python-主线程控制子线程-3

需求:在Python-主线程控制子线程结束-2的基础上,添加在子线程中执行操作并获取结果的功能。

一种常见的方法是使用队列(Queue)或者共享变量,在子线程中存储结果,然后在主线程中获取这些结果。这种方法可以确保线程间的数据共享是线程安全的。

# 修改后的程序,主线程可以获取子线程的结果
import threading
import time
import queue
from loguru import logger

exit_program = False


class WorkerThread(threading.Thread):
    def __init__(self, result_queue):
        super().__init__()
        self.stop_event = threading.Event()
        self.result_queue = result_queue

    static_variable = 0

    def run(self):
        thread_id = threading.get_ident()
        print(f"Worker thread {thread_id} has started.")
        while not self.stop_event.is_set():
            print(f"Worker thread {thread_id} is running.")
            # Simulate some work
            result = self.do_work()
            self.result_queue.put(result)
            time.sleep(1)
        print(f"Worker thread {thread_id} has stopped.")

    def increment_static_variable(cls):
        cls.static_variable += 1

    def do_work(self):
        # Simulate some work
        self.increment_static_variable()
        return self.static_variable

    def stop(self):
        self.stop_event.set()
        self.join()  # 等待子线程结束


def end_child_thread():
    try:
        if worker_thread.is_alive():
            worker_thread.stop()
            logger.info(f"Stopping worker thread {worker_thread.ident}...")
            if worker_thread.is_alive():
                logger.info(f"Worker thread {worker_thread.ident} is still active")
        else:
            logger.info(f"Worker thread {worker_thread.ident} doesn't exist ..")
    except Exception as e:
        logger.info("中止线程失败:" + e)


def key_listener():
    keyboard_thread_id = threading.get_ident()  # 获取键盘监听线程的ID
    global worker_thread  # 声明为全局变量
    # global result_queue
    print("""
    Press '0' to stop worker thread, 
          '1' to start a new worker thread,
          '2' to end the program.
    ...""")
    while True:
        print(f"Keyboard listener thread {keyboard_thread_id} has started.")
        command = input("请输入指令~")
        if command == '0':
            logger.info(f"工作线程状态{worker_thread}")
            end_child_thread()
            logger.info(f"工作线程状态{worker_thread}")
        elif command == '1':
            try:
                if worker_thread.is_alive():
                    pass
                else:
                    worker_thread = WorkerThread(result_queue)
                    worker_thread.start()
                    logger.info(f"Started new worker thread {worker_thread.ident}")
            except Exception as e:
                logger.info("新建工作线程失败:" + e)
        elif command == '2':
            end_child_thread()
            global exit_program
            exit_program = True
            break
        else:
            pass
        time.sleep(0.1)


if __name__ == '__main__':
    result_queue = queue.Queue()
    main_thread_id = threading.main_thread().ident
    logger.info(f"Main thread {main_thread_id} has started~")

    worker_thread = WorkerThread(result_queue)
    keyboard_thread = threading.Thread(target=key_listener)  # 创建键盘输入监听线程

    keyboard_thread.start()  # 启动键盘输入监听线程
    worker_thread.start()

    logger.info(f"Keyboard monitor thread {keyboard_thread.ident} has started~")
    logger.info(f"worker thread {worker_thread.ident} has started~")

    try:
        while not exit_program:
            if not result_queue.empty():
                result = result_queue.get()
                print("主线程获取的子线程结果:", result)
            else:
                # print("Main thread didn't get any result")
                pass
    except:
        print("手动停止程序...")
        worker_thread.stop()  # 在主线程退出时停止子线程
        worker_thread.join()  # 等待子线程结束

    print('exit')

    # 主线程退出
    logger.info(f"Main thread {main_thread_id} is exiting~")

 

猜你喜欢

转载自blog.csdn.net/Scarlett2025/article/details/132445696