Flask控制树莓派传感器:线程仅能启动一次的问题求解
解决Flask控制树莓派传感器扫描启停的线程复用问题
这个问题我之前碰到过好多次,核心问题就是你现在复用了同一个线程实例和事件对象——线程确实只能被启动一次,而且stopevent一旦被set()之后,如果不重置或者换新的,下次启动线程时wait()会直接返回,根本进不了扫描循环。
咱们可以这么改,核心思路是每次启动扫描时创建新的线程和事件实例,而不是复用旧的:
关键修改点
- 不要把线程和事件设为固定的全局变量,而是用两个全局变量存储当前运行的线程和对应事件,每次启动时重新赋值
- 在
start路由里先检查是否已有线程在运行,避免重复启动导致的错误 - 在
stop路由里,线程结束后清空全局变量,方便下次创建新实例
修改后的完整代码
import threading from flask import Flask, request, url_for, redirect, render_template def scan(number, duration): # 这里写你的传感器扫描逻辑,比如模拟打印扫描状态 print(f"Scanning with number={number}, duration={duration}") class LoopThread(threading.Thread): def __init__(self, name, event): super(LoopThread,self).__init__() self.name = name self.event = event self.number = 20 self.duration = 1 def run(self): print('Starting Thread-'+ str(self.name)) while not self.event.wait(timeout=1.0): self.loop_process() print('Stopping Thread-'+ str(self.name)) def loop_process(self): scan(self.number, self.duration) app = Flask(__name__) # 用全局变量存储当前运行的线程和事件,初始为None current_thread = None current_event = None @app.route("/") def index(): print("home page") return render_template('home.html') @app.route("/start") def start(): global current_thread, current_event # 先检查是否已有线程在运行,避免重复启动 if current_thread is not None and current_thread.is_alive(): print("Scan is already running!") return redirect(url_for('index')) # 创建新的事件和线程实例 current_event = threading.Event() # 线程名用递增数字区分,也可以用时间戳/线程ID thread_name = 1 if current_thread is None else int(current_thread.name) + 1 current_thread = LoopThread(thread_name, current_event) current_thread.start() print(f"Started new thread: Thread-{thread_name}") return redirect(url_for('index')) @app.route("/stop") def stop(): global current_thread, current_event if current_thread is None or not current_thread.is_alive(): print("No scan is running!") return redirect(url_for('index')) # 设置事件停止线程循环 current_event.set() # 等待线程完全结束 current_thread.join() # 清空全局变量,为下次启动做准备 current_thread = None current_event = None print("Scan stopped successfully") return redirect(url_for('index')) if __name__ == '__main__': app.run("0.0.0.0", debug=True)
额外说明
- 线程名的处理:这里用了简单的递增数字,你也可以用
threading.get_ident()或者时间戳生成唯一标识,线程名仅用于日志区分,不影响核心功能 - 状态检查:在启动和停止路由里加了运行状态判断,避免用户重复点击触发异常
- 事件对象:每次启动都创建新的
Event,比重置旧事件的clear()更稳妥,逻辑也更清晰
内容的提问来源于stack exchange,提问作者Willnil Phoon
相关产品推荐
相关产品推荐

