зависание потока последовательного порта - PullRequest
1 голос
/ 07 августа 2011

Я получил приведенный ниже код с веб-сайта, и этот способ чтения последовательного порта - мой единственный вариант, потому что событие 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 голосов
/ 07 августа 2011

Когда вы закрываете порт в StopReading (), это вызывает исключение в _serialPort.Read (...).

Не уверен, какой именно, но это не TimeOut.Ваш текущий код позволяет избежать этого, и тогда ваш поток и ваше приложение будут уничтожены.

Поэтому добавьте catch(Exceptiopn ex) вокруг цикла while в ReadPort ().

0 голосов
/ 07 августа 2011

Два вопроса на первый взгляд.

Во-первых, вы создали одноэлементный класс, который предоставляет подписку на события.Это опасно, потому что вы должны отслеживать любого из подписчиков.В противном случае они могут быть никогда не выпущены.Это, вероятно, то, что происходит в вашем случае.

Во-вторых, когда вы управляете чем-то "IDisposable", вы должны позаботиться об этом.Таким образом, SerialPort должен быть расположен внутри реализации IDisposable в вашем классе.Однако в одноэлементном классе это не имеет никакого смысла.

Одноэлементный шаблон следует использовать только для централизованных пассивных ресурсов и никогда не размещать «активные» объекты, события и т. Д.

Надеюсь, это поможет.

...