`
yuanlanxiaup
  • 浏览: 852496 次
文章分类
社区版块
存档分类
最新评论

C# 串口操作系列(2) -- 入门篇,为什么我的串口程序在关闭串口时候会死锁 ?

 
阅读更多

第一篇文章我相信很多人不看都能做的出来,但是,用过微软SerialPort类的人,都遇到过这个尴尬,关闭串口的时候会让软件死锁。天哪,我可不是武断,算了。不要太绝对了。99.9%的人吧,都遇到过这个问题。我想只有一半的人真的解决了。另外一半的人就睁只眼闭只眼阿弥佗佛希望不要在客户那里出现这问题了。

你看到我的文章,就放心吧,这问题有救了。我们先回顾一下上一篇中的代码

为什么会死锁呢,并发冲突。

我们要了解一下SerialPort的实现和串口通讯机制,在你打开串口的时候,SerialPort会创建一个监听线程ListenThread,在这个线程中,等待注册的串口中断,当收到中断后,会调用DataReceived事件。调用完成后,继续进入循环等待,直到串口被关闭退出线程。

我们的UI主线程如何做的呢,首先创建一个窗体,然后执行了Application.Run(窗体实例)。是这样把,这里的Application.Run就是创建了一个消息循环,循环的处理相关的消息。

这里我们就有了2个线程,UI主线程、串口监听线程。那么你在DataReceived处理数据的时候,就需要线程同步,避免并发冲突,什么是并发冲突?并发冲突就是2个或多个并行(至少看上去像)的线程运行的时候,多个线程共同的操作某一线程的资源,在时序上同时或没有按我们的预计顺序操作,这样就可能导致数据混乱无序或是彼此等待完成死锁软件。

而串口程序大多是后者。为什么呢,看看我们的例子中DataReceived做了什么?首先读取数据,然后就是调用this.Invoke方法更新UI了。这里Invoke的时候,监听线程将等待UI线程的标志,等到后,开始操作UI的资源,当操作完成之前,监听线程也就停在DataReceived方法的调用这里,如果这个时候。并发了关闭串口的操作会如何呢?SerialPort的Close方法,会首先尝试等待和监听线程一样的一个互斥体、临界区、或是事件(不确定.net用的哪种)。那这个同步对象什么时候释放呢?每次循环结束就释放,哦。循环为什么不结束呢?因为这一次的循环操作执行到DataReceived之后,执行了Invoke去更新界面了,那Invoke怎么又没有执行完成呢?看上去很简单的几行代码。虽然我没仔细研读过.net的Invoke原理,但我猜测是通过消息的方式来同步的,这也是为什么这么多的类,只有控件(窗体也是控件的一种,.net在概念上,颠覆了微软自己的概念,传统的win32编程,是说所有的控件都是个window,只是父窗体不同,表现形式不同,但都是基于系统消息队列的,.net出于更高的抽象,正好反过来了。呵呵)才有Invoke方法了。(委托自己的Invoke和这个不同)

我猜测控件/窗体的Invoke是SendMessage方式实现的,那么发送消息后就会等待消息循环来处理消息了。如果你直接去关闭串口了。你点击按钮本身也会被转换成消息WM_CLICK,消息循环在处理按钮的WM_CLICK时候,调用你按钮的OnClick方法,进而触发调用你的ButtonClose_Click事件,这都是同步调用的,你的主线程,处理消息的过程,停在了这个Click事件,而你的Click事件又去调用了SerialPort的Close方法,Close方法又因为和串口监听线程的同步信号量关联在一起需要等待一次的while结束,而这个while循环中调用了DataReceived方法,这个方法中调用了Invoke,也就是发送了消息到消息队列等待结果,但消息循环正在处理你的关闭按钮事件等待退出。

实在太复杂了,这个情况下,你想要真的关闭串口成功,就需要while中的DataReceived方法调用结束释放同步信号,就需要执行完Invoke,就需要执行消息循环,幸运的是,我们真的有办法执行消息循环来打破僵局。Application.DoEvents()。还好,不幸中的万幸。可是问题又来了,你能让Invoke结束,但你无法确定是否在你调用消息循环后,你的某一时刻不会再次并发,可能由于单cpu的串行操作模拟并行中,又把时间片先分给了优先级高的串口监听线程呢?是有可能的。所以,我们就需要一点方法来避免再次invoke窗体。优化后不会司机的例子如下,我们修改DataReceived方法,关闭方法,并定义2个标记Listening和Closing。

至此,不会再出现关闭死锁问题了。

希望这篇文章能解你的燃眉之急,非常高兴能与读者分享我层遇到,大多数人都遇到的这个问题。如果说的不明白,欢迎讨论。

后续的有关通讯程序底层设计的文章会讲述一个具有丰富扩展性,但有设计简介的万能通讯库,支持网络、蓝牙、串口通讯、并口通讯。但不要指望我都实现出来了,我只是设计出这个框架。

示例代码

//append by wuyazhe @2011-5-26

上面有一点疏漏,源自第一篇,结果到这里还是没修改,源码中有一行,需要修改一下。

//发送按钮中

buf.Add(byte.Parse(m.Value));

要修改为

buf.Add(byte.Parse(m.Value,System.Globalization.NumberStyles.HexNumber));

分享到:
评论

相关推荐

    C#.NET串口通信C# 串口操作C#与51单片机串口通信技术文档资料(15个).zip

    011.C# 串口操作系列(2) -- 入门篇,为什么我的串口程序在关闭串口时候会死锁 ?.doc 012.C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。.doc 013.C#_.net环境下与单片机串行通信的实践.doc 014....

    解决了关闭串口时死锁的CSerialPort类

    与2016-12-20日在其基础上修改了其中关串口卡死现象,添加十六进制与ASCII之间互转函数,觉得蛮好用的推荐给大家 如需转载请标明原始出处:http://blog.csdn.NET/itas109 QQ技术交流群:129518033 这是一份优秀的类...

    操作系统课程设计--死锁

    操作系统课程设计--死锁 操作系统课程设计--死锁 操作系统课程设计--死锁

    操作系统-死锁.pptx

    操作系统原理 第3章 进程管理 操作系统-死锁全文共26页,当前为第1页。 第7讲 进程死锁 2022/6/20 2 今日主题 什么是死锁?(了解) 死锁防止(熟悉) 死锁避免(掌握) 死锁检测和恢复(熟悉) [重点]:死锁必要...

    操作系统实验报告--模拟死锁避免程序

    设计模拟实现死锁避免的程序,要求: 1,输入并显示资源类型数,进程数,每类资源的个体数; 2,输入每个进程对每类资源的最大需求量,已分量,算出其剩余需求量。算出系统每类资源的当前剩余量;显示输入和计算出的...

    VS2005串口开发SerialPort通讯代码(解决死锁,含换肤功能比较经典)

    此代码是我接触vs2005 c#以来第一次自己认为比较经典完美的代码, 比较适合初学者用。源码部分来源于CSDN, 大部分参照网络其他有关文章关于处理串口经常出现问题编写,已解决反复调用串口意外造成死锁问题。串口...

    解决了关闭死锁的CSerialPort类项目

    1.它解决了,串口关闭时出现死锁不响应问题,可以直接用到开发的项目上。 2.并且是扩展了的串口助手,具有通信协议编辑和使用功能, 3.软件升级检测,值得做软件升级例子使用。 4.最重要的是源代码很不错,很值得...

    操作系统-死锁

    从进程同步的概念可以知道,当并发进程需要竞争使用资源或需要相互协作向前推进时,如果... 死锁是所有操作系统都面临着的潜在问题,操作系统除了需要预防死锁、避免死锁外,还需要能够检测死锁,并从死锁中进行恢复。

    c#串口调试助手(含源码:串口类、XML类、数据库类)

    欢迎反馈建议,其中包含了串口类、XML类、数据库类等功能。程序中使用线程处理数据接收用以解决SerialPort类死锁问题。

    操作系统实验--死锁的避免程序.doc

    操作系统实验--死锁的避免程序.doc

    微软SerialPort秘籍[SerialPort为什么死锁程序的分析]

    微软 MS 死机 SerialPort CE 既然是秘籍,显然是写一些大家不常找到的,MSDN里遗漏提示大家注意的东西。 用过.net 2.0中,自带...就会监听线程在等待,执行到界面操作,界面又要求关闭监听线程然后关闭串口。死锁了。

    .net串口通讯防死锁

    网上的很多相关的串口的源码是有问题的,至少有很多的bug,特别是死锁的问题大部分都没有解决,如果你也正好遇到这个问题,或许可以帮你解决燃眉之急,当然程序难免有些小错误,欢迎提出,谢谢。

    银行家算法避免死锁源代码(C#篇)

    本文档是使用C#编写的银行家算法避免死锁的程序设计。里面包含数组初始化,利用递归判断输入整数,输出安全序列等函数,希望对大家有帮助。如有错误,请多多指教~

    操作系统实验--死锁

    关于操作系统的实验,大家可以借鉴一下!我觉得还是很有帮助的!

    C#进程监控,监视程序是否崩溃、死锁?

    监控进程状态,无界面、托盘图标。

    1操作系统-死锁.pptx

    01 死锁的基本概念 02 资源的分布图(RAG) 03 处理死锁的方法 目 录 1操作系统-死锁全文共16页,当前为第2页。 死锁的基本概念 01 1操作系统-死锁全文共16页,当前为第3页。 基本概念 死锁的定义:一组进程中,每...

    银行家算法避免死锁 C# 操作系统课程设计

    本次课程设计通过编写和调试一个仿真模拟银行家算法避免死锁的程序,观察产生死锁的条件,并采用银行家算法,有效地避免死锁的发生。这是我们的操作系统课程设,用.net做的。 银行家算法避免死锁,其中有三个模块,...

    操作系统常用的死锁程序

    计算机操作系统第三版关于死锁的问题,程序代码

    C# 串口接收数据中serialPort.close()死锁的实例

    有各种这样的说法,有的说定义一个接收数据的标志,如果在执行关闭程序是进行判断,如果数据接收完了就关闭串口,没有的话继续执行,但是经过亲自测试并没有什么卵用,最后自己研究invoke的时候发现还有Begininvoke...

Global site tag (gtag.js) - Google Analytics