串口线程挂起

时间:2011-08-07 04:56:50

标签: c# multithreading serial-port hang

我从网站上获得了以下代码,这种串口读取方式是我唯一的选择,因为DataReceived事件通常不起作用。但是这个代码有问题,如果我关闭应用程序,同时转移应用程序永远挂起,但我不明白为什么?既不冻结也不中止线程工作。实际中止线程会导致程序崩溃。

public class CommPort
{
    SerialPort _serialPort;
    Thread _readThread;
    bool _keepReading;

    //begin Singleton pattern
    static readonly CommPort instance = new CommPort();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static CommPort()
    {
    }

    CommPort()
    {
        _serialPort = new SerialPort();
        _readThread = null;
        _keepReading = false;
    }

    public static CommPort Instance
    {
        get
        {
            return instance;
        }
    }
    //end Singleton pattern

    //begin Observer pattern
    public delegate void EventHandler(string param);
    public EventHandler StatusChanged;
    public EventHandler DataReceived;

    private void StartReading()
    {
        if (!_keepReading)
        {
            _keepReading = true;
            _readThread = new Thread(new ThreadStart(ReadPort));
            _readThread.Start();
        }
    }
    private void StopReading()
    {
        if (_keepReading)
        {
            _keepReading = false;
            _serialPort.Close();
            //_readThread.Join();   //block until exits
            _readThread.Abort();
            //_readThread = null;
        }
    }
    private void ReadPort()
    {
        while (_keepReading)
        {
            if (_serialPort.IsOpen)
            {
                byte[] readBuffer = new byte[_serialPort.ReadBufferSize + 1];
                try
                {
                    // If there are bytes available on the serial port,
                    // Read returns up to "count" bytes, but will not block (wait)
                    // for the remaining bytes. If there are no bytes available
                    // on the serial port, Read will block until at least one byte
                    // is available on the port, up until the ReadTimeout milliseconds
                    // have elapsed, at which time a TimeoutException will be thrown.
                    int count = _serialPort.Read(readBuffer, 0, _serialPort.ReadBufferSize);
                    String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);
                    DataReceived(SerialIn);
                }
                catch (TimeoutException)
                {
                }
            }
            else
            {
                TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
                Thread.Sleep(waitTime);
            }
        }
    }


    /// <summary> Open the serial port with current settings. </summary>
    public void Open()
    {
        Close();

        try
        {
            _serialPort.PortName = Properties.Settings.Default.COMPort;
            _serialPort.BaudRate = Properties.Settings.Default.BPS;
            _serialPort.Parity = Properties.Settings.Default.Parity;
            _serialPort.DataBits = Properties.Settings.Default.DataBit;
            _serialPort.StopBits = Properties.Settings.Default.StopBit;
            _serialPort.Handshake = Properties.Settings.Default.HandShake;

            // Set the read/write timeouts
            _serialPort.ReadTimeout = 50;
            _serialPort.WriteTimeout = 50;

            _serialPort.Open();
            StartReading();
        }
        catch (IOException)
        {
            StatusChanged(String.Format("{0} does not exist", Properties.Settings.Default.COMPort));
        }
        catch (UnauthorizedAccessException)
        {
            StatusChanged(String.Format("{0} already in use", Properties.Settings.Default.COMPort));
        }
        catch (Exception ex)
        {
            StatusChanged(String.Format("{0}", ex.ToString()));
        }

        // Update the status
        if (_serialPort.IsOpen)
        {
            string p = _serialPort.Parity.ToString().Substring(0, 1); //First char
            string h = _serialPort.Handshake.ToString();
            if (_serialPort.Handshake == Handshake.None)
                h = "no handshake"; // more descriptive than "None"

            StatusChanged(String.Format("{0}: {1} bps, {2}{3}{4}, {5}",
            _serialPort.PortName, _serialPort.BaudRate,
            _serialPort.DataBits, p, (int)_serialPort.StopBits, h));
        }
        else
        {
            StatusChanged(String.Format("{0} already in use", Properties.Settings.Default.COMPort));
        }
    }

    /// <summary> Close the serial port. </summary>
    public void Close()
    {
        StopReading();
        StatusChanged("connection closed");
    }
    public bool IsOpen
    {
        get
        {
            return _serialPort.IsOpen;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

当您在StopReading()中关闭端口时,它将在_serialPort.Read(...)中导致异常。

不确定哪一个确切但它不是TimeOut。你当前的代码让你逃脱,那就是你的线程和你的应用程序被杀死的时候。

因此,在ReadPort()中的while循环周围添加catch(Exceptiopn ex)

答案 1 :(得分:-1)

乍一看有两个问题。

首先,您创建了一个公开事件订阅的单例类。这很危险,因为你应该跟踪任何订阅者。否则他们可能永远不会被释放。这可能就是你的情况。

其次,当你管理“IDisposable”时,你应该注意它。因此,SerialPort应该放在类中的IDisposable实现中。但是,这在单身人士课程中没有任何意义。

单例模式应仅用于集中式被动资源,绝不应用于托管“活动”对象,事件等。

希望这有帮助。