2016-12-31 22 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