0

Why app is still working, when i close it.
I guess it is caused by reading of data from serial port.

Serial Port number is choosed from ComboBox.
Function WriteData update checkboxes depending on data from serial port.
Here's extract:

    // Choosing of communication port from ComboBox
    private void comboBoxCommunication_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (serialPort.IsOpen)
        {
            serialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);
            serialPort.Close();
        }
        try
        {
            ComboBoxItem cbi = (ComboBoxItem)comboBoxKomunikacia.SelectedItem;
            portCommunication = cbi.Content.ToString();
            serialPort.PortName = portCommunication;
            serialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);
            serialPort.BaudRate = 2400;
            serialPort.Open();
            serialPort.DiscardInBuffer();
        }
        catch (IOException ex)
        {
            MessageBox.Show(ex.ToString(), "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    // Close the window
    private void Window_Closed(object sender, EventArgs e)
    {
        if (serialPort.IsOpen)
        {                
            serialPort.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(Recieve);                
            serialPort.Close();
        }
    }

    // Data reading
    private delegate void UpdateUiTextDelegate(char text);
    private void Recieve(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        if (serialPort.IsOpen)
        {
            try
            {
                serialPort.DiscardInBuffer();
                char c = (char)serialPort.ReadChar();
                Dispatcher.Invoke(DispatcherPriority.Send,
                    new UpdateUiTextDelegate(WriteData), c);                    
            }
            catch(IOException ex)
            {
                MessageBox.Show(ex.ToString(), "Error!", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
    }

    // Update of checkboxes
    private void WriteData(char c) { ... }
hradecek
  • 2,455
  • 2
  • 21
  • 30
  • Any other threads? Can you verify (debugger / logger) that the Closed event is executing as expected? – H H Apr 08 '12 at 11:12
  • 1
    If the `serialPort` object is disposable, (and I think `SerialPort` is), then there's a fair chance you're not disposing of it properly in this code. You may want to re-structure it so that the scope of the variable is more controlled and can be wrapped in a `using` block. – David Apr 08 '12 at 11:14
  • @Henk Holterman - no other threads. App is closed normal, only when i start reading data from serial port, it is not closed properly. – hradecek Apr 08 '12 at 11:22
  • @David - i'm not sure, if i understand you. – hradecek Apr 08 '12 at 11:23
  • @David - when you want to use it event-driven then `using` is not an option. – H H Apr 08 '12 at 11:24
  • ReadChar synchronously reads data from the serial port. Check your app isn't blocked on that line. – Phil Apr 08 '12 at 12:23

1 Answers1

3

Your code is very likely to cause deadlock, blocking your program on the Close() call. The problem statement is the Dispatcher.Invoke() call. That call cannot complete until the UI thread has dispatched the call. The deadlock occurs when you call Close() and at the same time the DataReceived event is busy executing. The Close() call cannot complete because the event is running. The event handler cannot complete because Invoke() cannot complete because the UI thread is not idle, it is stuck in the Close() call. Deadlock city.

This is especially likely to happen in your code because it has a bug. You call DiscardInBuffer() in DataReceived. That throws away the received data so the next ReadChar() call is going to block for a while, waiting for some more data to get received, possibly forever if the device isn't sending anything anymore.

Fix this problem by deleting the DiscardInBuffer() call and by using Dispatcher.BeginInvoke() instead.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536