【发布时间】:2019-03-12 21:26:59
【问题描述】:
我正在使用 Raspberry Pi。
我有一个连接到 GPIO 引脚的按钮,以及一个连接到不同引脚的 LED。当按钮被按下时,一个函数被调用。 当该功能处于活动状态时,我希望 LED 闪烁,这需要一个后台线程。这实质上意味着我需要一个后台线程来在我的按钮处理程序运行时运行,并在我的按钮处理程序停止时停止。
我遇到的问题是通过运行下面的代码来证明的。代码以单个线程开始,但是当我点击按钮时,threading.active_count() 显示有 3 个线程正在运行(而不是预期的 2 个)。当我的线程完成运行后,我剩下 2 个后台线程 - 而不是预期的 1 个。
这是我的代码:
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import time
import threading
from threading import Thread, Event
#########################
# Function to Blink LED #
#########################
# Sample function that blinks the LED
def blink_led_func(led, stop_blinking):
while not stop_blinking.is_set():
print("Blinking LED...")
time.sleep(0.5)
#############
# Decorator #
#############
# Starts a background thread which blinks the LED, runs the decorated
# function, and when the function is done running, stops blinking the LED
class blink_led:
def __init__(self, function):
self.f = function
def __call__(self, channel):
stop = Event()
t = Thread(target=blink_led_func, args=(1, stop))
t.start()
self.f(channel)
stop.set()
t.join()
##################
# Button Handler #
##################
# Called when button is pressed
@blink_led
def btn_handler(channel):
print("Button pressed")
time.sleep(5)
##############
# Setup GPIO #
##############
# Setup pin
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP)
##############################
# Add Button Event Listeners #
##############################
GPIO.add_event_detect(12, GPIO.FALLING, callback=btn_handler, bouncetime=300)
########
# Main #
########
print("Listening for button presses...")
i = 0
while True:
time.sleep(1)
print("%s threads running" % threading.active_count())
这是我的代码的输出:
Listening for button presses...
1 threads running
1 threads running
1 threads running
Blinking LED...
Button pressed
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
Button pressed
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
Blinking LED...
3 threads running
Blinking LED...
2 threads running
2 threads running
2 threads running
这让我大吃一惊,因为在我的真实代码中,我有一个 Ctrl+C 处理程序,它说:使用 threading.Event() 通知所有线程死亡,等到active_count() == 1(只剩下主线程),清理 GPIO 并退出。理论上,这应该可以防止后台线程在清理后尝试使用 GPIO 库闪烁(这会导致异常),但在实践中,它会卡住等待其他线程死亡,因为总是有 2出于某种原因。
我做错了吗?还是 GPIO 库做了一些时髦的事情?
编辑:如果我注释掉 GPIO.add_event_detect 行并改为手动调用我的 btn_handler 函数 (btn_handler(1)),我就没有这个问题。函数运行完成后,我根据active_count() 减少到 1 个线程。不管是什么问题,似乎都与我在 GPIO 事件处理函数中启动线程有关。
还要注意,如果我不在 btn_handler 中启动后台线程,active_count() 在整个运行过程中保持为 1,据我所知,GPIO 库没有运行任何后台线程。
编辑 2:还请注意,当我减少到 2 个正在运行的线程时(当我只希望有一个时),如果我添加代码来检查线程的名称,额外的线程称为“Dummy-3 "
【问题讨论】:
标签: python python-3.x multithreading raspberry-pi raspberry-pi3