Я подозреваю, что это потому, что вы используете Thread.Abort для завершения потока - что обычно вызывает недовольство. Поведение потока при прерывании не предсказуемо. Из-за этого, поскольку последовательный порт является оболочкой над собственным кодом, существуют собственные ресурсы, представленные SafeHandle в .NET, которые неожиданно удаляются, и вы получаете исключение.
Вы можете думать о том, что происходит с вашей темой, как это:
- Вы начинаете свою тему
- вы открываете последовательный порт (который выделяет собственные ресурсы и использует SafeHandle (s) для удержания этих ресурсов)
- вы начинаете читать с последовательного порта
- затем в какой-то момент (неожиданно для вашего потока) вы вызываете Thread.Abort для него
- Скорее всего, код в вашем потоке в этот момент пытается получить доступ к последовательному порту (для чтения данных)
- поток уничтожается, а дескриптор последовательного порта неявно уничтожается
- вы получаете исключение из кода внутри функции ReadLine () последовательного порта, потому что дескриптор, который он имел, больше не действителен
Вы действительно должны использовать другой метод для прерывания потока, чтобы у вас была возможность закрыть и удалить последовательный порт.
Правильный способ закрыть ваш поток может быть реализован с помощью ManualResetEvent, например:
protected ManualResetEvent threadStop = new ManualResetEvent(false);
protected void ReadData()
{
SerialPort serialPort = null;
try
{
serialPort = SetupSerialPort(_serialPortSettings);
serialPort.Open();
string data;
while (serialPort.IsOpen)
{
try
{
data = serialPort.ReadLine();
if (data.Length > 0)
ReceivedData(serialPort, new ReceivedDataEventArgs(data));
}
catch (TimeoutException)
{
// No action
}
// WaitOne(0) tests whether the event was set and returns TRUE
// if it was set and FALSE otherwise.
// The 0 tells the manual reset event to only check if it was set
// and return immediately, otherwise if the number is greater than
// 0 it will wait for that many milliseconds for the event to be set
// and only then return - effectively blocking your thread for that
// period of time
if (threadStop.WaitOne(0))
break;
}
}
catch (Exception exc)
{
// you can do something here in case of an exception
// but a ThreadAbortedException should't be thrown any more if you
// stop using Thread.Abort and rely on the ManualResetEvent instead
}
finally
{
if (serialPort != null)
serialPort.Close();
}
}
protected void Stop()
{
// Set the manual reset event to a "signaled" state --> will cause the
// WaitOne function to return TRUE
threadStop.Set();
}
Конечно, при использовании метода событий, чтобы остановить поток, вы должны быть осторожным, чтобы включить проверку состояния события во все ваши длинные циклы или задачи . Если вы этого не сделаете, ваш поток может не реагировать на ваши установки события - пока он не выйдет из долгосрочного цикла или задачи и не получит возможность «увидеть», что событие установлено.