如何构建代码以启动可以 kill/replace 彼此的任务

How to structure code to be able to launch tasks that can kill/replace each other

我有一个 Python 程序可以执行以下操作: 1) 无休止地等待 com 端口命令字符 2) 在字符接收时,启动一个新线程来执行一段特定的代码

如果收到新命令,我需要做的是: 1)杀死前一个线程 2) 推出新的

我在这里和那里读到这样做不是正确的方法。 知道我需要在同一进程中执行此操作的最佳方法是什么,所以我想我需要使用线程 ...

我建议您采用两种不同的方法:

  • 如果您的进程都是从一个函数内部调用的,您可以set a timeout第一个函数。
  • 如果您是 运行 外部脚本,您可能想要 kill the process.

可能想运行把串口放在一个单独的线程中。当它接收到一个字节时,将该字节放入队列中。让主程序循环并检查队列以决定如何处理它。在主程序中,您可以使用 join 终止线程并启动一个新线程。您可能还想查看线程池,看看它是否是您想要的。

ser = serial.Serial("COM1", 9600)
que = queue.Queue()

def read_serial(com, q):
    val = com.read(1)
    q.put(val)

ser_th = threading.Thread(target=read_serial, args=(ser, que))
ser_th.start()

th = None
while True:
    if not que.empty():
        val = que.get()
        if val == b"e":
            break # quit
        elif val == b"a":
            if th is not None:
                th.join(0) # Kill the previous function
            th = threading.Thread(target=functionA)
            th.start()
        elif val == b"b":
            if th is not None:
                th.join(0) # Kill the previous function
            th = threading.Thread(target=functionB)
            th.start()
        elif val == b"c":
            if th is not None:
                th.join(0) # Kill the previous thread (functionA)
            th = threading.Thread(target=functionC)
            th.start()

try:
    ser.close()
    th.join(0)
except: 
    pass

如果您正在创建和加入很多线程,您可能只需要一个函数来检查 运行 的命令。

running = True
def run_options(option):
    if option == 0:
        print("Running Option 0")
    elif option == 1:
        print("Running Option 1")
    else:
        running = False

while running:
    if not que.empty():
        val = que.get()
        run_options(val)

让我通过添加我的代码结构示例来尝试更准确地回答我的问题。

假设同步函数 A 仍然是 运行,因为在内部等待特定事件,如果收到命令 "c",我需要停止函数 A 并启动函数 C。

 def functionA():
    ....
    ....
    call a synchronous serviceA that can take several seconds even more to execute
    ....
    ....


def functionB():
    ....
    ....
    call a synchronous serviceB that nearly returns immediately
    ....
    ....


def functionC():
    ....
    ....
    call a synchronous serviceC
    ....
    ....    


#-------------------

def launch_async_task(function):

    t = threading.Thread(target=function, name="async")
    t.setDaemon(True)
    t.start()


#------main----------

while True:
    try:
        car = COM_port.read(1)

        if      car == "a":
                    launch_async_task(functionA)

        elif    car == "b":
                    launch_async_task(functionB)

        elif    car == "c":
                    launch_async_task(functionC)

好吧,我终于用了一段代码,使用ctypes lib来提供某种杀死线程的功能。 我知道这不是一个干净的方法,但在我的例子中,线程没有共享资源,所以它不应该有任何影响......

如果有帮助,下面是一段很容易在网上找到的代码:

def terminate_thread(thread):
    """Terminates a python thread from another thread.

    :param thread: a threading.Thread instance
    """
    if not thread.isAlive():
        return

    exc = ctypes.py_object(SystemExit)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
        ctypes.c_long(thread.ident), exc)
    if res == 0:
        raise ValueError("nonexistent thread id")
    elif res > 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")