我有一个Winform程序,它在SerialPort
上执行一些异步IO。但是,我经常遇到程序卡住SerialPort.Close()调用的问题,这似乎是随机的。
我认为这是线程安全性问题,但是我不确定如何解决。我尝试使用端口打开/关闭功能添加/删除异步DataReceived处理程序,并丢弃端口上的输入和输出缓冲区,但是它似乎没有任何作用。我认为重要的SerialPort
代码如下:
using System;
using System.Collections.Generic;
using System.IO.Ports;
public class SerialComm
{
private object locker = new object();
private SerialPort port;
private List<byte> receivedBytes;
public SerialComm(string portName)
{
port = new SerialPort(portName);
port.BaudRate = 57600;
port.Parity = Parity.None;
port.DataBits = 8;
port.StopBits = StopBits.One;
receivedBytes = new List<byte>();
}
public void OpenPort()
{
if(port!=null && !port.IsOpen){
lock(locker){
receivedBytes.Clear();
}
port.DataReceived += port_DataReceived;
port.Open();
}
}
public void ClosePort()
{
if(port!=null && port.IsOpen){
port.DataReceived -= port_DataReceived;
while(!(port.BytesToRead==0 && port.BytesToWrite==0)){
port.DiscardInBuffer();
port.DiscardOutBuffer();
}
port.Close();
}
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try{
byte[] buffer = new byte[port.BytesToRead];
int rcvdBytes = port.Read(buffer, 0, buffer.Length);
lock(locker){
receivedBytes.AddRange(buffer);
}
//Do the more interesting handling of the receivedBytes list here.
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine(ex.ToString());
//put other, more interesting error handling here.
}
}
}
更新
感谢@Afrin的答案指出了UI线程的死锁情况(This blog post很好地描述了死锁情况,并提供了其他几个不错的技巧),我做了一个简单的更改,但还无法重现该错误!
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try{
byte[] buffer = new byte[port.BytesToRead];
int rcvdBytes = port.Read(buffer, 0, buffer.Length);
lock(locker){
receivedBytes.AddRange(buffer);
}
ThreadPool.QueueUserWorkItem(handleReceivedBytes);
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine(ex.ToString());
//put other, more interesting error handling here.
}
}
private void handleReceivedBytes(object state)
{
//Do the more interesting handling of the receivedBytes list here.
}
最佳答案
当您关闭它时它会挂起的原因是因为在您的SerialPort对象的事件处理程序中
您正在与主线程同步调用(通常是通过调用invoke)。 SerialPort的close方法等待其EventLoopRunner线程触发激发DataReceived/Error/PinChanged事件的终止。但是由于事件中您自己的代码也正在等待主线程响应,因此您将陷入死锁状态。
解决方案:使用begininvoke而不是invoke:
https://connect.microsoft.com/VisualStudio/feedback/details/202137/serialport-close-hangs-the-application
引用:http://stackoverflow.com/a/3176959/146622
编辑:
Microsoft链接已断开,因为它们已退出Connect。试试web.archive.org:
https://web.archive.org/web/20111210024101/https://connect.microsoft.com/VisualStudio/feedback/details/202137/serialport-close-hangs-the-application
关于C#Winform在SerialPort.Close上卡住,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8843301/