gpt4 book ai didi

c# - "Safe handle has been closed"带有 SerialPort 和 C# 中的线程

转载 作者:太空狗 更新时间:2023-10-29 20:12:09 27 4
gpt4 key购买 nike

大家下午好!

我有这个线程化的 SerialPort 包装器,它从串口读取一行。这是我的线程代码。

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
}
}
}
catch (ThreadAbortException)
{
if (serialPort != null)
serialPort.Close();
}
}

当我调用 myThread.Abort(); 时出现异常(没有行或代码引用)“安全句柄已关闭”。谁能发现我做错了什么?谢谢。

顺便说一下,我有一个 Start() 和一个 Stop(),它们分别创建线程和中止线程。

最佳答案

我怀疑这是因为您正在使用 Thread.Abort 来结束线程——这通常是不受欢迎的。当您中止时线程的行为是不可预测的。因此,由于串行端口是 native 代码的包装器,因此存在 native 资源(由 .NET 中的 SafeHandle 表示)意外处理,因此您会得到异常。

你可以这样想你的线程会发生什么:

  • 你开始你的话题
  • 您打开串行端口(它分配 native 资源并使用 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();
}

当然,当使用事件方法停止线程时,您必须注意在所有长时间运行的循环或任务中包含事件状态检查。如果您不这样做,您的线程可能不会响应您设置的事件 - 直到它退出长时间运行的循环或任务并有机会“看到”事件已设置。

关于c# - "Safe handle has been closed"带有 SerialPort 和 C# 中的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1319003/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com