树莓派Flask线程运行时串口读取线程无法并行的解决咨询
问题分析与解决方案
核心问题
你的代码存在两个关键问题导致串口线程无法正常运行:
- Flask启动阻塞主线程:
socketio.run()是阻塞式调用,你把它直接写在FlaskServer类的顶层代码中,当创建FlaskServer实例时,这行代码会立即执行,卡住主线程,导致串口线程无法正常并行执行。 - 线程目标设置错误:
FlaskThread的target设为Flask(类实例化),这不是一个可调用的方法,正确做法是指向Flask服务的启动方法。
另外还有两个次要问题:
- SocketIO事件处理中引用了未定义的
cycle变量,应该改为serialMessage。 - 全局变量
serialMessage没有线程安全保护,多线程读写可能引发数据混乱。
修正后的代码
from flask import Flask, render_template, request from flask_socketio import SocketIO, emit from threading import Thread, Lock import time import serial # 全局变量+线程锁,保证多线程访问安全 serialMessage = "" message_lock = Lock() class SerialReadProgram: def __init__(self): self._running = True def terminate(self): self._running = False def run(self): global serialMessage try: ser = serial.Serial("/dev/ttyS0", 9600, timeout=0.1) print("Serial Start") while self._running: # 读取串口数据 data = ser.read() if data: time.sleep(0.03) data_left = ser.inWaiting() data += ser.read(data_left) # 加锁更新全局变量 with message_lock: serialMessage = data.decode('utf-8', errors='ignore') print(serialMessage) time.sleep(0.01) # 降低循环频率,减少资源占用 except Exception as e: print(f"串口错误: {e}") finally: if 'ser' in locals(): ser.close() class FlaskServer: def __init__(self): self.app = Flask(__name__) self.socketio = SocketIO(self.app, cors_allowed_origins='*') self._setup_routes() self._setup_socket_events() def _setup_routes(self): @self.app.route('/', methods=('GET', 'POST')) def home(): if request.method == 'POST': message = request.form['message'] print(message) return render_template('index.html') def _setup_socket_events(self): @self.socketio.on('connect') def test_connect(): emit('after connect', {'data':'Connected'}) @self.socketio.on('Fetch For Data') def value_changed(): # 加锁读取全局变量 with message_lock: current_message = serialMessage emit('Updated Message', {'data': current_message}, broadcast=True) def run(self): # 启动Flask-SocketIO服务 self.socketio.run(self.app, host='0.0.0.0', allow_unsafe_werkzeug=True) # 启动串口线程 serial_read = SerialReadProgram() serial_thread = Thread(target=serial_read.run, daemon=True) serial_thread.start() # 启动Flask线程 flask_server = FlaskServer() flask_thread = Thread(target=flask_server.run, daemon=True) flask_thread.start() # 主线程保持运行,防止程序退出 while True: time.sleep(1)
关键修改说明
- 重构FlaskServer类:把路由和SocketIO事件处理封装到类的方法中,将
socketio.run()移到run()方法里,避免实例化类时直接阻塞主线程。 - 线程目标修正:Flask线程的
target指向flask_server.run方法,确保线程启动时执行服务启动逻辑。 - 线程安全处理:添加
Lock对象保护serialMessage的读写,避免多线程同时操作导致数据异常。 - 串口读取优化:添加异常捕获和串口关闭逻辑,防止程序崩溃;增加
timeout和循环休眠,减少资源占用。 - 修复变量错误:把SocketIO事件中的
cycle改为serialMessage,避免未定义变量报错。
运行说明
- 确保树莓派已安装依赖:
pip install flask flask-socketio pyserial - 准备好
templates/index.html页面,通过SocketIO监听Updated Message事件来接收串口数据并展示。
内容的提问来源于stack exchange,提问作者kaydrae
相关产品推荐
相关产品推荐

