ObjectDisposedException при прерывании потока, записывающего в последовательный порт - PullRequest
2 голосов
/ 17 августа 2010

Я написал приложение с функцией плагина, и если плагин не отвечает быстро на запрос на остановку, я вызываю Thread.Abort() в его рабочем потоке. Кажется, это работает большую часть времени, но недавно я обнаружил, что он выдает ObjectDisposedException, если поток прерывается во время записи в последовательный порт. С некоторыми драйверами USB-to-serial в Windows XP это даже вызывает синий экран смерти.

Я думаю, что могу использовать шаблон «производитель / потребитель», чтобы сделать так, чтобы рабочий поток не выполнял прямую запись в последовательный порт, но я хотел бы знать, есть ли какая-либо дополнительная информация о том, почему сбои последовательного порта вне.

Вот упрощенный пример, который воспроизводит проблему:

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);
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 17 августа 2010

Не уверен, что это поможет (у моего компьютера нет последовательных портов; не могу проверить), но это согласуется с моим комментарием.

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);
        }
    }
}
0 голосов
/ 17 августа 2010

Это точно не объясняет, что идет не так, но совет 4 в в этом посте от команды библиотеки базовых классов звучит так, как будто прерывание потока во время операций последовательного порта не поддерживается:

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

...