2016-12-31 84 views
0

我试图循环报警(文件beep.wav中),并显示一个警告。类属性没有得到正确分配

一旦警报被关闭,我想立即停止报警。

我试图它使用的线程控制报警的播放的解决方案。

然而,它抛出一个错误:

Traceback (most recent call last): 
    File "test.py", line 28, in <module> 
    thread.stop() 
    File "test.py", line 21, in stop 
    self.process.kill() 
AttributeError: 'AlarmThread' object has no attribute 'process' 

我真的不知道为什么这个错误会抛出,但它看起来像self.process是,由于某些原因,当AlarmThread.stop被称为未分配。

这是没有意义的我,从我的代码看起来thread.stopthread.start后只叫:

import subprocess 
import threading 

class AlarmThread(threading.Thread): 
    def __init__(self, file_name="beep.wav"): 
     super(AlarmThread, self).__init__() 
     self.file_name = file_name 
     self.ongoing = None 

    def run(self): 
     self.ongoing = True 
     while self.ongoing: 
      self.process = subprocess.Popen(["afplay", self.file_name]) 
      self.process.wait() 

    def stop(self): 
     if self.ongoing is not None: 
      self.ongoing = False 
      self.process.kill() 

thread = AlarmThread() 
thread.start() 
# show_alert is synchronous, an alert must be closed before the script continues 
show_alert("1 second timer") 

thread.stop() 
thread.join() 

回答

1

你有一个竞争条件。该线程没有时间启动,创建该进程并在您拨打thread.stop()时分配self.process。你可以在__init__初始化self.process并用它来确定进程是否真的有

import subprocess 
import threading 

class AlarmThread(threading.Thread): 
    def __init__(self, file_name="beep.wav"): 
     super(AlarmThread, self).__init__() 
     self.lock = threading.Lock() 
     self.file_name = file_name 
     self.ongoing = False 
     self.process = None 

    def run(self): 
     self.ongoing = True 
     while True: 
      with self.lock: 
       if not self.ongoing: 
        break 
       self.process = subprocess.Popen(["afplayer", self.file_name]) 
      self.process.wait() 

    def stop(self): 
     with self.lock: 
      if self.ongoing: 
       self.ongoing = False 
       if self.process: 
        self.process.kill() 


thread = AlarmThread() 
thread.start() 
# show_alert is synchronous, an alert must be closed before the script continues 
show_alert("1 second timer") 

thread.stop() 
thread.join() 
+0

宜'如果self.process'是一个'while not self.process:pass'来等待线程准备好被杀死? – theonlygusti

+0

此解决方案仍然无法正常工作。 – theonlygusti

+0

@theonlygusti - 我添加了一些锁以堵塞这些洞。它在我写的一些黑客测试中起作用。你可以在你的环境中测试吗? – tdelaney

0

是的,这是由竞争条件引起的。

The thread hasn't had time to start, create the process and assign self.process by the time you call thread.stop()

然而,我发现,在简单地等待,直到thread.process被分配依赖修复:

thread = AlarmThread() 
thread.start() 
while not thread.process: 
    time.sleep(0.1) 

show_alert(message) 

thread.stop() 
thread.join() 

我班也略有改变,以确保thread.process始终分配:

class AlarmThread(threading.Thread): 
    def __init__(self, file_name="beep.wav"): 
     super(AlarmThread, self).__init__() 
     self.file_name = file_name 
     self.ongoing = None 
     self.process = None 

    def run(self): 
     self.ongoing = True 
     while self.ongoing: 
      self.process = subprocess.Popen(["afplay", self.file_name]) 
      self.process.wait() 
      self.process = None 

    def stop(self): 
     if self.ongoing is not None: 
      self.ongoing = False 
      self.process.kill() 
+0

看着'run',设置'self.ongoing'和'self.process'实际分配(执行“afplay”需要大量时间)之间有一个窗口。由于'self.process = None',每个循环都存在差距。另外,'self.ongoing'只应该是True/False ...你将它设置为False,但检查None。 – tdelaney