Michel Feinstein
Michel Feinstein

Reputation: 14266

Error in SerialPort Closes Thread but don't change it's Status and don't raise an Exception

I am reading a SerialPort in a separate thread using the code below.

I open the Serial Port and try to read a line. Since there is nothing connected in the Serial Port there is an error. I was expecting some TimeoutException to be thrown, but NO! There are not Exceptions being thrown and the Task stops working!

As far as I know, a Task can be shutdown by returning from it, or throwing an exception, but this code doesn't do either. The task stops working and the Task Status remais as WaitingForActivation.

What's going on? I need to handle this kind of error in my application but I can't see any kind of Exception or error being reported by the SerialPort.

Also I tried to go into Tools/Options/Debugging and turn off "Enable Just My code (Managed only)" and this didn't do anything.

The code is: (I placed it inside a button click to make it easier to replicate.) (In order to run this you need a FTDI cable or something like it, and nothing connected to the cable).

private void Button_Click(object sender, RoutedEventArgs e)
    {
        if (Thread.CurrentThread.Name != "Main")
        {
            Thread.CurrentThread.Name = "Main";
        }

        Debug.WriteLine(string.Format("Started from thread '{0}'.", Thread.CurrentThread.Name));
        TestTask = Task.Run(() =>
            {
                Thread.CurrentThread.Name = "TestTask";
                int i = 0;
                Debug.WriteLine(string.Format("Started from thread '{0}'.", Thread.CurrentThread.Name));
                while (true)
                {
                    try
                    {
                        SerialPort serialPort = new SerialPort("COM14"); 
                        while (!serialPort.IsOpen) serialPort.Open(); // Try to open the SerialPort.
                        Debug.WriteLine(string.Format("From Thread '{0}', Try to read now:", Thread.CurrentThread.Name));
                        string s = serialPort.ReadLine(); // here's the error.
                        i++; // this line is never executed.
                        Debug.WriteLine(string.Format("From Thread '{0}', Loop Count : {1}", Thread.CurrentThread.Name, i));
                    }                        
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);                            
                    }
                }
            }
            );
        while(true)
        {
            Debug.WriteLine(string.Format("From Thread '{0}', TestTask Status: {1}.", Thread.CurrentThread.Name, TestTask.Status));
            Thread.Sleep(500);
        }
        //try // I tried this before the 'while(true)' above to see if there were any Exceptions being thrown to the "outside" but no, nothing here.
        //{
        //    TestTask.Wait();
        //}
        //catch(AggregateException ae)
        //{
        //    ae.Flatten();
        //}
    }

An output of the program is like this:

Output

Upvotes: 0

Views: 99

Answers (2)

Dean Seo
Dean Seo

Reputation: 5683

The reason why you get this issue might vary depending on what modules interact with the serial port.

However, there are a few things you need to go over to get what you expect from the code.

First of all, the TestTask is always waiting for activation as long as while(true) is there for infinite loop.

Second, SerialPort.Readline does not throw TimeOutException and wait until a line is received, unless you set the ReadTimeout propety to a non-zero value.

try-catch for exception in Task.Run has to work as it should. You can see it work in this extremely simple code example as follows:

var TestTask = Task.Run(() =>
{
    while (true)
    {
        try
        {
            throw new Exception();
        }                        
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);                            
        }
    }
});

Finally, you will still want to check how your VS debugger behaves when encountering any exceptions by looking at Debug - Exception...(Ctrl+Alt+E), in which its option columns can be different depending on whether Just My Code is enabled or not, in case you are confused. (I personally prefer to have it enabled).

If you want to catch all the exceptions your application throw no matter whether it'll be properly handled in the future or not, check Thrown column in that option window. That will cause VS debugger to break every time an exception is thrown.

Upvotes: 4

Michel Feinstein
Michel Feinstein

Reputation: 14266

The Thread was locked inside the ReadLine() method because there was no ReadTimeout defined. The Thread as indeed still executing and no errors or Exceptions were interfering with it.

I was just not expecting the method to block since the code documentation didn't specify that the method will block indefinitely, until a newline character is received. But the online documentation makes it clear:

By default, the ReadLine method will block until a line is received. If this behavior is undesirable, set the ReadTimeout property to any non-zero value to force the ReadLine method to throw a TimeoutException if a line is not available on the port.

Upvotes: 0

Related Questions