[求助]C# 串口事件接收高频次数据, sp.close()时就会程序会卡死.

jimodeduzou 2016-04-21 12:12:23
有相关开发经验的大侠们有遇到过同类问题吗?

目前要设计一个利用串口接收间隔为100~50ms的数据程序.
我用串口助手模拟以100ms间隔持续发送相同数据, 然后写程序利用串口接收数据事件对其数据进行单纯的接收.
如果不关闭发送端的话, 直接关闭接收端 (close() 方法), 程序就会随机性卡死在这条语句上.

因为在实际运作的时候, 发送端设备是无休止的向外高频发送数据, 我没有办法对设备进行任何操作. 只能被动接收.
这种情况下有什么好的办法可以解决吗?
另外是什么原因导致卡死呢?

接收事件的处理代码:

this.Invoke(updateSP_receiver, sp.ReadTo("\n")); //updateSP_receiver就是一个textbox接收string显示出来而已.
...全文
691 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
lovedogdog 2017-07-22
  • 打赏
  • 举报
回复
this.invoke改成this.begininvoke
qq_37799345 2017-03-07
  • 打赏
  • 举报
回复
怎么解决的呢,跪求啊
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
引用 9 楼 Yokeqi 的回复:
sp.DataReceived += sp_DataReceived; sp.DataReceived -= sp_DataReceived; 另外,代码真的好乱,没精神看~~
好了, 我已解决了. 就是消息队列多线程同步处理死锁的问题. 说了就是Invoke和接收事件摊上了随机点close时导致的死锁~ 我觉得这个问题对于那些没有经历过本地Windows编程的朋友估计都很难理解是咋回事.....汗. 也谢谢你了 同时上面那位高级兄台劈头盖脸也来了一通, 可惜对问题解决然并卵......
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
引用 9 楼 Yokeqi 的回复:
sp.DataReceived += sp_DataReceived; sp.DataReceived -= sp_DataReceived; 另外,代码真的好乱,没精神看~~
其实也不需要看我的代码, 我给的代码就两部分而已, 上半部分无非就是一个串口相关参数的预定义. 下半部分就是开关式的对串口执行打开, 关闭的操作. 每段操作成功后, 后面加入了一句界面信息回显而已. 数据接收根据我的设备发送数据特征采用ReadTo方法. 我的确认思路如下: 前提: 数据发送端一直发送, 不做任何操作. 只操作接收端. 1. 在sp.close()在非断点调试情况下, 是随即性卡死, 如果采用断点调试在close()处是百分百卡死. 2. 开始我怀疑是触发消息队列过多被阻塞, 这样的话在关闭端口前加入了 对消息订阅的取消显示是不行的. 可能会出现后续的消息没处理, 端口却关闭了. 所以出现了死锁. <--这是我目前的想法. 大侠, 你觉得呢?
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
引用 6 楼 sp1234 的回复:
DiscardInBuffer 这种东西干什么使用的?既然关闭了,就直接关闭就行了。 Thread.Sleep(500) 这种代码说明了你根本没有调试程序bug原因在哪里,在胡乱用“延时”来欺骗同事(其实你在这块不会编程调试,怕他们过早看出程序崩溃,丢人啊)。 你写 try...catch 然后直接“求人给一块儿瞎猜猜看代码”,说明你没有调试能力。真正程序员,直接就能在抛出异常的那一条代码上进行调试,要求助知道主动贴出调试画面来了。
兄弟, 很感谢你的回复, 你说的部分我也很清楚. 可能你看的比较急, 上面也说了 sp.DiscardInBuffer(); Thread.Sleep(500); 这两段是要注释掉的, 我发送出来的时候忘记了, 写这两段的原因并不是你想的那样, 而且我在测试卡死问题时加进去用来确认在执行close()时, MSDN给出的回复的是后台会先清除缓冲区, 执行关闭, 所以尝试加入了 DiscardInBuffer看是否因为高频问题, 导致后台清除动作循环锁死了. 你那边是否什么解决思路?还请帮忙讲讲
枫0子K 2016-04-21
  • 打赏
  • 举报
回复
sp.DataReceived += sp_DataReceived; sp.DataReceived -= sp_DataReceived; 另外,代码真的好乱,没精神看~~
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
引用 4 楼 Yokeqi 的回复:
你试试,在Close之前,把接收数据的事件给注销掉 -=. 还是不行的话应该是关闭的时候正在处理已接收到的数据得等待数据全部处理完,这个得再讨论。 先试试上面那个办法
这个我昨晚试了下面这样的: sp.close() 加上 使用了: sp.DataReceived -= new SerialDataReceivedEventHandler(sp_DataReceived); 而且我在调试的时候发现最后执行还是在sp.close上卡住. 然后我将其设置为生成Release的版本: 通过直接点击运行程序, 程序虽然不会卡死, 但是在点击关闭端口的时候, 会有一定几率的崩溃, 错误如下: 问题签名: 问题事件名称: CLR20r3 问题签名 01: Winform_20160406_SerialPort.exe 问题签名 02: 1.0.0.0 问题签名 03: 57186f89 问题签名 04: System 问题签名 05: 4.6.1055.0 问题签名 06: 563c0ff8 问题签名 07: 28cf 问题签名 08: e4 问题签名 09: System.IO.IOException OS 版本: 6.1.7601.2.1.0.256.1 区域设置 ID: 2052 其他信息 1: f048 其他信息 2: f048c3d51e07894ff4464d1457b48696 其他信息 3: 0385 其他信息 4: 0385e1c047ca342542bf7454e2e95397 不知道到底为什么会出现这样问题. 难道是接收频次太高的问题? 我调成500ms暂时没发现这个问题. 但是100ms下 我开两个串口助手自己发送接收 是完全没有问题. 关闭 打开很流畅.
  • 打赏
  • 举报
回复
说得明白一点把,你的编程习惯,让人瞎猜代码,无法迅速调试。
  • 打赏
  • 举报
回复
DiscardInBuffer 这种东西干什么使用的?既然关闭了,就直接关闭就行了。 Thread.Sleep(500) 这种代码说明了你根本没有调试程序bug原因在哪里,在胡乱用“延时”来欺骗同事(其实你在这块不会编程调试,怕他们过早看出程序崩溃,丢人啊)。 你写 try...catch 然后直接“求人给一块儿瞎猜猜看代码”,说明你没有调试能力。真正程序员,直接就能在抛出异常的那一条代码上进行调试,要求助知道主动贴出调试画面来了。
  • 打赏
  • 举报
回复
在 openSerialPort 里边关闭串口,你这叫程序啊? 先把流程整理一下,少来这种 if 判断,该是open的处理过程就open,该是close的处理过程就close,别乱混合。
枫0子K 2016-04-21
  • 打赏
  • 举报
回复
你试试,在Close之前,把接收数据的事件给注销掉 -=. 还是不行的话应该是关闭的时候正在处理已接收到的数据得等待数据全部处理完,这个得再讨论。 先试试上面那个办法
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
引用 1 楼 wukaiping870123 的回复:
这么一段代码谁能看出来有何问题?
我上了关闭 打开代码 其中这两行注视掉: sp.DiscardInBuffer(); Thread.Sleep(500);
jimodeduzou 2016-04-21
  • 打赏
  • 举报
回复
问题是其他代码全是控件啥. 没有任何计算处理. 这是打开 关闭代码:
private bool openSerialPort()
        {
            //初始化
            if (sp == null)
            {
                portName = listBox_spList.SelectedItem.ToString();
                baudRate = int.Parse(cbo_baudRate.SelectedItem.ToString());
                parity = (Parity)Enum.Parse(typeof(Parity), cbo_parity.SelectedItem.ToString()); //字符串到枚举指定类型的转换
                dataBits = int.Parse(cbo_dataBits.SelectedItem.ToString());
                stopBits = (StopBits)Enum.Parse(typeof(StopBits), cbo_stopBits.SelectedItem.ToString());

                updateSP_receiver = new del_updateSP_receiver(update_tb_receiver);

                sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits); //初始化串口
                sp.ReadTimeout = 5000;
                sp.WriteTimeout = 5000;
                //sp.ReceivedBytesThreshold = 26;
                sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); //事件订阅
            }

            try
            {
                if (!sp.IsOpen) //打开
                {
                    sp.Open();
                    btn_openSP.Text = "关闭串口";
                    tb_sendstr.Enabled = true; //打开发送输入box
                    msgUpdate(portName + "打开成功!");
                }
                else //关闭
                {
                    sp.DiscardInBuffer();
                    Thread.Sleep(500);
                    sp.Close();
                    btn_openSP.Text = "打开串口";
                    sp.Dispose(); //释放sp使用的资源
                    sp = null; //销毁sp
                    tb_sendstr.Enabled = false; //关闭发送输入box
                    msgUpdate(portName + "关闭成功!");
                }
            }
            catch (Exception i)
            {
                sp.Dispose();
                sp = null;
                msgUpdate(portName + "操作失败!," + "异常原因:\r\n" + i);
                return false;
            }
            return true;
        }
火星大能猫 2016-04-21
  • 打赏
  • 举报
回复
这么一段代码谁能看出来有何问题?

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧