我正在编写一个侦听声音事件的应用程序(使用通过Open Sound Control传入的消息),然后根据这些事件暂停或恢复程序执行。我的结构大多数时间都在工作,但总是在主循环中爆炸,所以我猜它是一个线程问题。这是我正在谈论的通用简化版本:
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)会导致一些套接字通信,这也涉及到线程。
在我的代码中经常发生的事情是主循环并不总是在声音事件发生后从它停止的地方拾取。它适用于许多事件,但最终它只是没有回答。
关于如何在线程之间构建这种通信的任何建议?
更新:
好吧,我想我已经明白了。这是一个似乎有效的修改。有一个监听器线程定期将值放入Queue对象。有一个检查程序线程继续检查队列中查找值,一旦它看到它设置一个布尔值到其相反的状态。该布尔值控制循环线程是继续还是等待。我不完全确定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()
答案 0 :(得分:4)
1)你的Loop.loop函数的线程应该被设置为一个守护程序线程,以便它与你的主线程一起退出(所以你不必每次要关闭你的程序时都杀掉python进程) 。要做到这一点,只需在调用线程的“启动”函数之前输入loop.setDaemon(True)。
2)线程之间进行通信的最简单且防错的方法是使用Queue。在线程上将一个项目放在该队列中,另一个线程将一个项目取出,对该项目执行某些操作然后终止(或获得另一个工作)
在python中,Queue可以是从全局列表到python的内置Queue对象的任何东西。我推荐python Queue,因为它是线程安全且易于使用的。