我正在使用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)
),则不会出现此问题。函数运行完后,根据,我只有1个线程active_count()
。无论问题是什么,似乎都与我在GPIO事件处理函数中启动线程有关。
还要注意,如果我没有在btn_handler中启动后台线程,则active_count()
在整个运行过程中都保持为1,据我所知,GPIO库未在运行任何后台线程。
编辑2:还请注意,当我只有2个正在运行的线程(当我只希望有一个)时,如果我添加代码以检查线程的名称,则多余的线程称为“ Dummy-3”
RPi.GPIO
的事件处理在隐式启动的专用线程中执行,以处理执行的回调:
RPi.GPIO运行第二个用于回调函数的线程。这意味着回调函数可以与主程序同时运行,以立即响应边缘。
无论注册了多少个回调,这些线程中只有一个:
回调函数按顺序运行,而不是同时运行。这是因为只有一个线程用于回调,每个线程都按照其定义的顺序运行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句