防止Python中的多个线程实例

时间:2017-04-16 18:04:21

标签: python python-2.7 raspberry-pi python-multithreading

我使用Raspberry Pi从按钮和一些LED上运行电机。 LED必须根据某些变量执行闪烁模式,并让它们在自己的线程中运行以允许代码继续工作(当然,我从here得到了这个想法。)

问题在于,取决于用户按下按钮的速度(一个序列需要多次推动来设置速度),释放按钮时停止的LED线程有时会在最后一个之前再次调用终止。

这意味着,我认为现在有两个线程,所以当发送阻止LED线程中的run()动作的命令时,我相信其中一个线程(或者两者都可能)没有#39 ; t得到停止命令,因此在按钮释放后,LED保持闪烁(正如线程所要求的那样)。

所以我认为我正在寻找的方法是确保一次只运行一个LED线程实例。我认为最简单的方法是让LED线程首先终止可能正在运行的LED线程的所有其他实例。我喜欢这个,因为无论哪个灯光从线程中闪烁,它都会停止,并且最近动作中需要闪光的新线程接管。

我该怎么做?我一直在查看isActive()功能,但我猜不到它的概念,所以我不知道如何使用它。

这是LED线程供参考。其他.py脚本使用flash_led()函数调用它,并使用stop_led()函数停止:

## leds.py. This is imported into the scripts that run the motors and buttons

# LED control Thread (Which-LED, Desired-State On/Off/Flash, Flash-On-Duration, Flash-Off-Duration, Number-Of-Flashes)

class LEDFlash(Thread):

    #Initial parameters for an LED Flash command, overwritten by led_flash()
    led_pin = led_dict["red_led_1"] #from a dict earlier in the script
    flash_on_duration = 1.0
    flash_off_duration = 1.0

    def __init__(self):
        super(LEDFlash, self).__init__()
        self.keep_flashing = True

    def run(self):
        while self.keep_flashing:
            GPIO.output(self.led_pin, GPIO.HIGH)
            time.sleep(self.flash_on_duration)
            GPIO.output(self.led_pin, GPIO.LOW)
            time.sleep(self.flash_off_duration)

    def stop_flash(self):
        self.keep_flashing = False


def flash_led(led, on_time, off_time): # 'flash_led.' added to make flash_thread accessible from the stop_led() function
    flash_led.flash_thread = LEDFlash()
    flash_led.flash_thread.led_pin = led_dict[str(led)]
    flash_led.flash_thread.flash_on_duration = on_time
    flash_led.flash_thread.flash_off_duration = off_time
    flash_led.flash_thread.start()

def stop_led():
    flash_led.flash_thread.stop_flash()

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你问的是如何在python中停止一个线程。我喜欢这个主题的现有帖子:Is there any way to kill a Thread in Python?

话虽如此,你可能还想在释放按钮时考虑 not 停止线程的选项,因为创建线程是一个相对昂贵的操作,并且,如上面的线程所述,你可能不应该直接杀死线程 - 你会想要等待它响应一个事件。如果沿着那条路走下去,你也可能有一个状态变化的事件,并且只是通知现有的线程它应该处于什么状态,而不是创建一个刚刚进入同一状态的全新线程。 。

答案 1 :(得分:1)

来自@MichaelNelson的建议只有一个处理LED的永久线程,这是最好的方法。

但是要直接解决您的问题,您可以在flash_led()

的开头添加此代码
if hasattr(flash_led, 'flash_thread'):
  stop_led()

这将确保在创建新线程之前销毁旧线程(如果有)。

编辑:旧线程和新线程仍有可能在短时间内处于活动状态;它不应该是你的问题,但如果是,你可以说:

if hasattr(flash_led, 'flash_thread'):
  stop_led()
  flash_led.flash_thread.join() # wait until old thread completes

你绝对不想杀死一个线程;正如here所解释的那样,终止一个线程是非常危险和混乱的,并且应该只在非常罕见的情况下完成,其中没有其他方法可行。你的情况是完全标准的,可以使用完全干净的代码处理,而不需要使用任何丑陋的东西。

另外,我建议用全局变量替换function属性;它们大致相当,但是当有人读取代码时,全局变量更容易跟踪。换句话说,只需写:

flash_thread = None
def flash_led(led, on_time, off_time):
    # you need global statement at the beginning of every function
    # in which you modify a global variable
    global flash_thread
    if flash_thread is not None:
      flash_thread.stop_flash() # probably no need to define stop_led() 
    flash_thread = LEDFlash()
    flash_thread.led_pin = ...
    ...

更好的是重构代码以将其存储为某个控制器对象的实例属性,但这需要更多的工作。