class属性未正确分配

时间:2016-12-31 17:00:18

标签: python multithreading macos subprocess python-2.x

我正在尝试循环警报(在文件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.stop仅在thread.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()

2 个答案:

答案 0 :(得分:1)

你有竞争条件。线程没有时间开始,创建流程并在您致电self.process时指定thread.stop()。您可以在self.process中初始化__init__并使用它来查看流程是否真的存在

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()

答案 1 :(得分:0)

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

  

线程没有时间开始,创建流程并在您拨打self.process时分配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()