理想的线程结构问题(涉及多线程通信)

2 投票
1 回答
730 浏览
提问于 2025-04-16 06:24

我正在写一个应用程序,它会监听声音事件(通过使用开放声音控制传递的消息),然后根据这些事件来暂停或恢复程序的执行。我的结构大部分时间都能正常工作,但在主循环中总是出问题,所以我猜这可能是线程的问题。下面是我所说的一个简单的、通用的版本:

import time, threading

class Loop():
    aborted = False

    def __init__(self):
        message = threading.Thread(target=self.message, args=((0),))
        message.start()

        loop = threading.Thread(target=self.loop)
        loop.start()


    def message(self,val):

        if val > 1:
            if not self.aborted:
                self.aborted = True
                # do some socket communication            
            else:
                self.aborted = False
                # do some socket communication


    def loop(self):
        cnt = 0

        while True:
            print cnt
            if self.aborted:
                while self.aborted:
                    print "waiting"
                    time.sleep(.1);
            cnt += 1


class FakeListener():
    def __init__(self,loop):
        self.loop = loop
        listener = threading.Thread(target=self.listener)
        listener.start()

    def listener(self):
        while True:
            loop.message(2)
            time.sleep(1)



if __name__ == '__main__':

    loop = Loop()

    #fake listener standing in for the real OSC event listener
    listener = FakeListener(loop)

当然,这段简单的代码看起来运行得很好,所以它并没有完全展示我真实代码的情况,但你大概明白我的意思。这里没有提到的是,每次循环暂停和恢复(通过设置aborted=True/False)都会涉及一些套接字通信,这也涉及到线程。

在我的代码中,总是发生这样的情况:主循环在声音事件后并不总是能从上次停止的地方继续。它在处理多个事件时能正常工作,但最终总会出现不响应的情况。

有没有什么建议可以帮助我更好地组织线程之间的这种通信?

更新:

好的,我想我找到了办法。这里有一个修改版本,看起来能正常工作。现在有一个监听线程,它会定期向一个队列对象中放入一个值。还有一个检查线程,它会不断检查这个队列,寻找这个值,一旦找到,就会把一个布尔值设置为相反的状态。这个布尔值控制循环线程是继续执行还是等待。

不过,我不太确定q.task_done()这个函数在这里是干什么的。

import time, threading
import Queue

q = Queue.Queue(maxsize = 0)

class Loop():
    aborted = False

    def __init__(self):
        checker = threading.Thread(target=self.checker)
        checker.setDaemon(True)
        checker.start()

        loop = threading.Thread(target=self.loop)
        loop.start()


    def checker(self):
        while True:
            if q.get() == 2:
                q.task_done()
                if not self.aborted:
                    self.aborted = True
                else:
                    self.aborted = False


    def loop(self):
        cnt = 0

        while cnt < 40:
            if self.aborted:
                while self.aborted:
                    print "waiting"
                    time.sleep(.1)
            print cnt
            cnt += 1
            time.sleep(.1)


class fakeListener():

    def __init__(self):
        listener = threading.Thread(target=self.listener)
        listener.setDaemon(True)
        listener.start()

    def listener(self):
        while True:
            q.put(2)
            time.sleep(1)



if __name__ == '__main__':

    #fake listener standing in for the real OSC event listener
    listener = fakeListener()

    loop = Loop()

1 个回答

4

嗯……我不太明白你的问题,但我会尽量解释一下我认为你需要做的事情来解决你的问题。

1) 你的 Loop.loop 函数的线程应该设置为守护线程,这样它就会和主线程一起退出(这样你就不需要每次关闭程序时都去杀掉 Python 进程)。要做到这一点,只需在调用线程的“start”函数之前加上 loop.setDaemon(True)。

2) 在线程之间沟通最简单、最可靠的方法是使用队列(Queue)。一个线程会往队列里放一个东西,另一个线程则会从队列里取出这个东西,处理完后就结束(或者去做其他事情)。

在 Python 中,队列可以是任何东西,从全局列表到 Python 内置的队列对象。我推荐使用 Python 的队列,因为它是线程安全的,而且使用起来很简单。

撰写回答