Home Dashboard Directory Help
Search

SerialPort.Close() hangs the application by Vince Noga


Status: 

Closed
 as By Design Help for as By Design


4
0
Sign in
to vote
Type: Bug
ID: 202137
Opened: 9/13/2006 12:11:37 PM
Access Restriction: Public
3
Workaround(s)
view
5
User(s) can reproduce this bug

Description

Calling SerialPort.Close() on an open serial port hangs the application.
Details
Sign in to post a comment.
Posted by markoni on 8/1/2009 at 1:56 AM
Change "this.Invoke" in to "this.BeginInvoke".
Posted by Microsoft on 5/11/2007 at 5:09 PM
Thanks Vnoga and Nobugz, and we apologize for failing to post a workaround earlier!

As described in the blog Nobugz linked to, there is deadlock between the UI thread and the threadpool threads. So the workaround you described -- closing the port on another thread -- will work, but you can also replace Control.Invoke calls with Control.InvokeLater calls. This workaround is a less invasive and a good practice generally.

Thanks,
Kim
Posted by nobugz on 5/11/2007 at 2:19 PM
Kim Hamilton has posted a diagnostic and a workaround for this problem on this blog post:

http://blogs.msdn.com/bclteam/archive/2006/10/10/Top-5-SerialPort-Tips-_5B00_Kim-Hamilton_5D00_.aspx
Posted by Vince Noga on 9/19/2006 at 5:45 AM
Closing the port in another thread is the way to go.
Posted by Vince Noga on 9/18/2006 at 12:24 PM
Well, from futher testing, the workaround I posted today (09/18/2006) doesn't work 100% of the time. It made the hang less likely, but it can still happen.
Sign in to post a workaround.
Posted by Unregistered User on 5/7/2007 at 3:42 PM
I'm confused. The Issue Status says "Closed (By Design)". If SerialPort->Close() is "Designed" to work this way then it should be renamed to:

SerialPort->HangApp(Intermittency=>50%).

It would have saved me days of debugging if it were named more appropiately.

Seriously, I know MS doesn't want to support "Legacy" serial devices (or anything not PnP) and wishes these devices would just go away, but there are a gazillion serial port devices still out there and manufacturers are still making new Serial Port based products which programmers still have to make apps for.

Unless MS can talk H/W Manufacturers out of making Serial devices, you gotta help us out.

So how do we get this Issue reopened?
Posted by Vince Noga on 9/18/2006 at 5:15 AM
Another (very lame) workaround is to update the user-interface (UI) in a different thread. It should not be this difficult to collect data from a serial port and display it in the UI.

*** WARNING ***
This simple example is just that, a simple example. It does not prevent data loss from the serial port to the UI.
***************

        private AutoResetEvent are = new AutoResetEvent(false);
        private bool portOpen = false;
        private string serialData = "";

        private void button1_Click(object sender, EventArgs e)
        {
            if (!serialPort1.IsOpen)
            {
                try
                {
                    serialPort1.PortName = "COM1";
                    serialPort1.BaudRate = 9600;
                    serialPort1.DataBits = 7;
                    serialPort1.Parity = System.IO.Ports.Parity.Even;
                    serialPort1.StopBits = System.IO.Ports.StopBits.One;
                    serialPort1.Open();
                    portOpen = true;
                    Thread t = new Thread(new ThreadStart(MonitorPort));
                    t.IsBackground = true;
                    t.Start();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
                }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                //Tell MonitorPort() to stop updating the UI
                portOpen = false;

                //Wait for MonitorPort() to signal that it's done
                are.WaitOne();

                serialPort1.Close();
            }
        }

        //Declare a method signature that can be Invoked
//        private delegate void UIUpdater(string s);
        private delegate void UIUpdater();

        //A method that has the same signature as UIUpdater()
//        private void UIUpdate(string s)
        private void UIUpdate()
        {
            textBox1.Text = serialData;
        }

        private void MonitorPort()
        {
            try
            {
                //All this thread does is write the serial data to the UI.
                //This simple example is not written to prevent data loss!
                while (portOpen)
                {
                    this.Invoke(new UIUpdater(UIUpdate));
                    Thread.Sleep(100);
                }
            }
            finally
            {
                //Signal that the thread is terminating
                are.Set();
            }
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //If continuous data from the device, application can hang when
         //SerialPort.Close() is called.
            //this.Invoke(new UIUpdater(UIUpdate),
            // new object[] { serialPort1.ReadExisting() });

            //Save the data to an object where .Invoke() is not required.
            //This simple example is not written to prevent data loss!
            serialData = serialPort1.ReadExisting();
        }
Posted by Personal Information Withheld on 9/15/2006 at 7:32 AM
A (very lame) workaround is to do the close in a new thread. I haven't tested trying to reopen the port and I'm not sure that it would be a good thing to do!