ObjectDisposedException when I abort a thread that's writing to the serial port
I've written an application with a plug-in feature, and if a plug in doesn't respond quickly to a stop request, I call Thread.Abort()
on its worker thread. This seems to work most of the time, but I recently discovered that it throws an ObjectDisposedException
if the thread is aborted while it's writing to the serial port. With some USB-to-serial drivers in Windows XP, it even causes a blue screen of death.
I think I can use a producer/consumer pattern to make it so that the worker thread doesn't directly write to the serial port, but I'd like to know if there's any more detail available about why the serial port freaks out.
Here's a simplified example that reproduces the problem:
using System;
using System.IO.Ports;
using System.Threading;
class Program
{
private static SerialPort port = new SerialPort();
static void Main(string[] args)
{
port.PortName = "COM1";
开发者_运维知识库 port.Open();
for (int i = 0; i < 10; i++)
{
var workerThread = new Thread(Loop);
workerThread.Start();
Thread.Sleep(1000);
workerThread.Abort();
Thread.Sleep(1000);
Console.Out.WriteLine("Finished {0}.", i);
}
}
static void Loop()
{
for (int i = 0; i < 1000000; i++)
{
port.Write(new byte[] {0, 0, 0, 0, 0, (byte)(i % 256)}, 0, 6);
}
}
}
It doesn't explain exactly what goes wrong, but tip 4 in this post from the base class library team makes it sound like aborting the thread during serial port operations is unsupported:
We’ve had a few bugs reporting sudden shutdown in apps – most often it’s caused by performing unsupported behavior such as interrupting a thread accessing the SerialPort. The specific symptom in this case is an ObjectDisposedException thrown on a separate thread that cannot be caught.
Not sure if this would help (my computer has no serial ports; can't test), but this goes along with my comment.
using System;
using System.IO.Ports;
using System.Threading;
class Program
{
private static SerialPort port = new SerialPort();
private static readonly object locker = new object();
private static bool abort;
static void Main(string[] args)
{
port.PortName = "COM1";
port.Open();
for (int i = 0; i < 10; i++)
{
var workerThread = new Thread(Loop);
lock (locker)
{
abort = false;
}
workerThread.Start();
Thread.Sleep(1000);
lock (locker)
{
abort = true;
}
Thread.Sleep(1000);
if (workerThread.IsAlive)
{
// Last-ditch effort.
workerThread.Abort();
}
Console.Out.WriteLine("Finished {0}.", i);
}
}
static void Loop()
{
for (int i = 0; i < 1000000; i++)
{
lock (locker)
{
if (abort)
{
return; // or break would work here in this case...
}
}
port.Write(new byte[] {0, 0, 0, 0, 0, (byte)(i % 256)}, 0, 6);
}
}
}
精彩评论