C#程序串口读取过程中打开新窗体出现冻结问题求解决方案
问题核心原因
SerialPort.DataReceived事件默认运行在后台工作线程,所有窗体创建、显示/隐藏、控件修改等UI操作必须在UI线程执行,你当前直接在后台线程触发窗体创建和显示,已经引发线程死锁,是窗体冻结的根因。processData方法逻辑存在缺陷:当队列数据不足14字节时,空的byteArray会被强制遍历赋值,引发空引用异常,未捕获的异常会导致程序无响应。- 用到的
Queue是非线程安全类,多线程读写时会出现未知异常。
修复方案
1. 把UI操作封送到UI线程执行
修改processData中打开新窗体的逻辑,通过主窗体的Invoke方法将操作调度到UI线程:
if (bits13[2]&&reentrant==0) { reentrant = 1; // 新增UI线程调度 this.Invoke((Action)(() => { Form1 formita = new Form1(this); formita.Show(); })); }
2. 修复Form1的Load逻辑
Form的Load事件本身就运行在UI线程,不需要额外调用Invoke,直接修改为:
private void Form1_Load(object sender, EventArgs e) { mainy2.Hide(); }
3. 修正processData的执行逻辑
所有数据处理逻辑必须放在队列数据足够的判断分支内,数据不足时直接返回:
public void processData() { byte[] byteArray = new byte[14]; if (recievedData.Count <= 13) { // 数据不足直接返回 return; } for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = recievedData.Dequeue(); } // 后续所有数据转换、判断、Writing调用逻辑都放在这里执行 // ... 原有处理逻辑 ... }
4. 替换为线程安全的队列
将非线程安全的Queue替换为ConcurrentQueue,避免多线程并发读写异常:
// 替换原有Queue定义 private ConcurrentQueue<byte> recievedData = new ConcurrentQueue<byte>();
对应修改出队逻辑:
// 原有byteArray[i] = recievedData.Dequeue();替换为 recievedData.TryDequeue(out byte currentByte); byteArray[i] = currentByte;
优化建议
原代码中14次BitArray转换逻辑完全重复,可以通过循环实现,大幅精简代码量,降低出错概率。
内容的提问来源于stack exchange,提问作者Miguel Rodmen
相关产品推荐
相关产品推荐

