如何以合适的方式关闭线程和启动线程?

2024-04-23 11:03:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要运行并用输入关闭线程。这里,它使用输入函数来处理输入。如果输入为启动。然后,运行recv方法,因为thread else输入是close将第二个参数设置为False。假值表示接收器内的循环停止。但是,我的控制台一直开着。它应该关闭控制台。因为它是循环的终点。你知道吗

class Device():
    def open(self, port, baudrate):
        try:
            return serial.Serial(port, baudrate)
        except SerialException as e:
            error = re.findall(r"'(.*?)'", str(e))

            self.__error['port'] = error[0]
            self.__error['description'] = error[1]

            return None

    def __state(self, open):
        if open is None:
            if self.__error['description'] == 'Access is denied.':
                return True
            elif self.__error['description'] == 'Port is already open.':
                return True
            else:
                return False
        else:
            return True

    def write(self, device, command):
        if self.__state(device):
                device.write(command.encode('UTF-8') + b'\r')
        else:
            print(self.__error['port'] + ' ' + self.__error['description'])

    def recv(self, device, open = True):
        while open:    
            if self.__state(device):
                buffer = device.readline()

                print(buffer)

                time.sleep(1)
            else:
                print(device[0] + ' ' + device[1])

                time.sleep(1)

device = Device()

serial = device.open('COM12', 9600)

while True:
    command = input('Enter a command: ')
    if command == 'start':
        t = threading.Thread(target=device.recv, args=(serial,))
        t.start()
    elif command == 'close':
        device.recv(serial, False)
    elif command == 'imei':
        device.write(serial, 'AT+CGSN')

Tags: selffalsetruereturnifportdevicedef
1条回答
网友
1楼 · 发布于 2024-04-23 11:03:21

如果我理解你的问题,你是在尝试这样做:

  1. 开始程序并发出start命令时,一个新线程(thread-2)开始在device对象的recv()方法中执行
  2. 主线程(thread-1)在事件循环中继续并显示另一个输入提示。同时,Thread-2在recv()中永远循环
  3. 在Thread-1中,然后发出close命令,目的是中断Thread-2,使其脱离循环并停止向终端写入输出。你知道吗

如果这是正确的,那么问题就出现在步骤3中:当Thread-1调用device.recv(serial, False)时,它对Thread-2的执行没有影响。这是因为,当创建线程并调用start方法时:

t = threading.Thread(target=my_func)
t.start()

新线程将开始执行my_func,但它将使用自己的调用堆栈、指令指针和寄存器来执行。稍后,当Thread-1调用device.recv()时,它将导致堆栈帧被推送到Thread-1的调用堆栈上。该调用与已经在Thread-2中运行的调用完全不同。你知道吗

线程共享许多资源:文本、数据和BSS内存段、打开的文件描述符和信号(以及一些其他资源)。调用堆栈不是共享的。你知道吗

如果您需要在线程之间进行通信,threading库提供了几个有帮助的选项。一个这样的选项是threading.Event,它可以用来在线程之间传递一些事件的发生。你可以这样使用它:

term_event = threading.Event()

class Device:
    def recv(self, device):
        while not term_event.isSet():
            if self.__state(device):
                buffer = device.readline()
                print(buffer)
                time.sleep(1)
            else:
                print(device[0] + ' ' + device[1])
                time.sleep(1)
        term_event.clear()

这将创建一个event对象,该对象由进程中的所有线程共享。线程1可以使用它来告诉线程2何时退出。然后,您需要像这样更改事件循环:

while True:
    command = input('Enter a command: ')
    if command == 'start':
        t = threading.Thread(target=device.recv, args=(serial,))
        t.start()
    elif command == 'close':
        term_event.set()
    elif command == 'imei':
        device.write(serial, 'AT+CGSN')

代替第二次调用recv方法,juist set共享的event对象,Thread-2将其解释为退出的信号。在退出之前,Thread-2调用term_event.clear(),以便稍后可以启动一个新线程。你知道吗


1:由于线程是同一进程的一部分,它们实际上占用了内核分配的相同内存空间。因此,每个线程的私有堆栈(理论上)都可以由该程序中的任何其他线程访问。

相关问题 更多 >