Rob*_*der 4 c# multithreading pos-for-.net safehandle
所以这是一个相当小的问题,有一个很大的解释.正如标题所述,我得到一个未处理的异常,告诉我我的安全句柄已经关闭.我可能要做的是使用越来越多的代码编辑这篇文章几次,以帮助我诊断出问题所在.
我正在使用POS for .NET为我的RFID和MSR设备制作服务对象.虽然我的设备是相同的,但我有2个不同的虚拟COM端口芯片可以与这些设备通信.一个是Silicon实验室,另一个是FTDI.我想使用POS for .NET的即插即用功能,所以我给它提供了我的硬件ID.因为它是即插即用的,我有完整的硬件路径可供我使用,然后我可以使用对PInvoke的调用创建一个SafeFileHandle并使用该SafeFileHandle创建一个FileStream.FTDI芯片不允许我直接与设备通信,所以我必须得到设备的友好名称,然后使用互斥锁拉出COM端口,然后创建一个SerialPort实例.这一步很好,很棒.作为一个FYI,我试图使用两个芯片的友好名称来获取COM端口,并且使用Ports GUID使用SetupAPI.GetDeviceDetails不会列出Silicon Labs(由于一些奇怪的原因).我不确定那个,因为在设备管理器中Silicon实验室设备类Guid是Ports GUID.
好吧,因为SerialPort和FileStream都有一个Stream对象,我决定使用它来读取和写入该端口.问题在于,如果我向MSR设备发送RFID命令,则MSR设备不会响应任何内容.因此,如果我使用此代码,int fromReader = ReaderStream.ReadByte();我的线程将被阻止.这是一个阻塞调用,需要至少1个字节才能继续.所以我环顾四周,似乎唯一的解决方案是使用单独的线程并设置超时.如果发生超时,则中止线程.
Thread t = new Thread(new ThreadStart(ReadFromStream));
t.Start();
if (!t.Join(timeout))
{
t.Abort();
}
Run Code Online (Sandbox Code Playgroud)
(t.Abort被try/catch包围无济于事,因为它没有解决我删除它的问题)
ReadFromStream是RFID设备中的抽象方法.这是其中一个实现
protected override void ReadFromStream()
{
var commandLength = USN3170Constants.MIN_RESPONSE_LENGTH;
var response = new System.Collections.Generic.List<byte>(USN3170Constants.MIN_RESPONSE_LENGTH);
for (int i = 0; i <= commandLength; i++)
{
int fromReader = ReaderStream.ReadByte();
if (fromReader == -1) break; //at end of stream
response.Add((byte)fromReader);
if (response.Count > USN3170Constants.DATA_LENGTH_INDEX && response[USN3170Constants.DATA_LENGTH_INDEX] > 0)
{
commandLength = response[USN3170Constants.DATA_LENGTH_INDEX] + 3;
}
}
streamBuffer = response.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
(int fromReader = ReaderStream.ReadByte();被try/catch包围.只有它捕获的是被中止的线程异常,所以我把它拿出来了)
上面的代码是我怀疑问题所在.但奇怪的是,我有一个单元测试,我觉得它很适合微软测试应用程序.
(FYI QUADPORT是FTDI芯片组)
PosExplorer posExplorer;
DeviceCollection smartCardRWs;
[Test]
public void TestQuadPortOpen()
{
posExplorer = new PosExplorer();
smartCardRWs = posExplorer.GetDevices(DeviceType.SmartCardRW, DeviceCompatibilities.CompatibilityLevel1);
//if using quadport one item is the MSR and the other is the RFID
//because of that one of them will fail. Currently the first Device in the collection is the the RFID, and the second is MSR
Assert.GreaterOrEqual(smartCardRWs.Count, 2);
//Hardware Id: QUADPORT\QUAD_SERIAL_INTERFACE
foreach(DeviceInfo item in smartCardRWs)
{
Assert.AreEqual("QUADPORT\\QUAD_SERIAL_INTERFACE", item.HardwareId);
}
SmartCardRW rfidDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[0]);
SmartCardRW msrDevice = (SmartCardRW)posExplorer.CreateInstance(smartCardRWs[1]);
rfidDevice.Open();
Assert.AreNotEqual(ControlState.Closed, rfidDevice.State);
rfidDevice.Close();
try
{
msrDevice.Open();
Assert.Fail("MSR Device is not a RFID Device");
}
catch
{
Assert.AreEqual(ControlState.Closed, msrDevice.State);
}
rfidDevice = null;
msrDevice = null;
}
Run Code Online (Sandbox Code Playgroud)
当我运行该测试时,我没有得到SafeFileHandle异常.实际上测试通过了.
所以我不知道如何追查这个错误.由于我将在另一个我正在创建的程序中使用此服务对象,我可能最终会在该程序中使用此测试中的代码.不过我觉得微软测试应用程序或多或少是"黄金标准".它真的......可能不是.但它确实对我的目的有用,所以我觉得这是我的代码而不是他们的代码的问题.
关于如何缩小范围的任何技巧?仅供参考我试过使用调试器但是走开Open Code就不会发生错误.我也走了更新状态计时器,它也没有抛出错误.一旦我点击继续,我就会得到例外.我转向Just My Code和Loaded Symbols,它告诉我"此模块的调试信息中缺少源信息"
这个问题(特别是对SerialPort实例的引用)听起来很可疑,就像http://connect.microsoft.com/VisualStudio/feedback/details/140018/serialport-crashes-after-disconnect-of-usb-中记录的问题一样.com-port.
据我所知,在非永久性SerialPort(例如,与USB设备相关联的一个)的情况下,当端口"意外消失"时,与其相关联的基础流将被丢弃.如果端口上有活动的读取或写入操作,则后续调用SerialPort.Close会导致您提到的异常,但是在Microsoft的代码中运行的异常发生在另一个线程上,并且无法从您的内部捕获码.(任何"最后机会"异常处理程序仍然可以看到你绑定到AppDomain上的UnhandledException事件.)
链接文档中似乎有两种基本的解决方法样式.在这两种情况下,在打开端口后,您将存储对打开端口的BaseStream实例的引用.然后,一种解决方法会抑制该基本流上的垃圾回收.另一个显式调用基本流上的Close,捕获在该操作期间抛出的任何异常,然后在SerialPort上调用Close.
编辑:对于它的价值,在.NET框架V4.5下,似乎Microsoft Connect站点上没有任何记录的变通方法可以完全解决问题,尽管它们可能会降低它出现的频率.:-(
| 归档时间: |
|
| 查看次数: |
22784 次 |
| 最近记录: |