理想的线程结构问题(涉及多线程通信)
我正在写一个应用程序,它会监听声音事件(通过使用开放声音控制传递的消息),然后根据这些事件来暂停或恢复程序的执行。我的结构大部分时间都能正常工作,但在主循环中总是出问题,所以我猜这可能是线程的问题。下面是我所说的一个简单的、通用的版本:
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 个回答
嗯……我不太明白你的问题,但我会尽量解释一下我认为你需要做的事情来解决你的问题。
1) 你的 Loop.loop 函数的线程应该设置为守护线程,这样它就会和主线程一起退出(这样你就不需要每次关闭程序时都去杀掉 Python 进程)。要做到这一点,只需在调用线程的“start”函数之前加上 loop.setDaemon(True)。
2) 在线程之间沟通最简单、最可靠的方法是使用队列(Queue)。一个线程会往队列里放一个东西,另一个线程则会从队列里取出这个东西,处理完后就结束(或者去做其他事情)。
在 Python 中,队列可以是任何东西,从全局列表到 Python 内置的队列对象。我推荐使用 Python 的队列,因为它是线程安全的,而且使用起来很简单。