我正在使用通过COM互操作包装器公开的第三方dll。然而,其中一个COM调用经常被冻结(至少不会返回)。为了至少使我的代码更加健壮,我异步地结束了调用(_getDeviceInfoWaiter是一个ManualResetEvent)
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork +=
(sender, eventArgs) =>
{
var deviceInfo = _myCom.get_DeviceInfo(0);
_serialNumber = deviceInfo.SerialNumber;
_getDeviceInfoWaiter.Set();
};
backgroundWorker.RunWorkerAsync();
var waitFifteenSecondsForGetInfo = new TimeSpan(0, 0, 0, 15);
_getDeviceInfoWaiter.WaitOne(waitFifteenSecondsForGetInfo, true);
if(String.IsNullOrEmpty(_serialNumber))
throw new ArgumentNullException("Null or empty serial number. " +
"This is most likely due to the get_DeviceInfo(0) COM call freezing.");但是,对任何COM组件的下一次调用都会冻结代码。有什么是我没有想到的,还是有什么办法让我的主线不死?
更新
基本上,这是一个COM调用,每当一个新设备插入到PC上,就会调用它,这样我们就可以适当地记录信息。但是,正如我所说的,如果这个组件正在等待,任何 COM组件都会冻结(如果第三方锁定了我们自己锁的自定义COM )。
更新2
上面的代码确实有效,并将UI线程的挂起推迟到下一个COM调用。这种解决方法的原因是因为var deviceInfo = _myCom.get_DeviceInfo(0);已经锁定了UI线程。但是,此信息并不重要,只用于日志记录,因此这种方法允许“15秒后放弃并继续前进”场景。
这里的另一个解决方法是在x秒后找到取消COM调用的方法??
发布于 2012-04-25 18:30:14
更新-在OP的第二次更新之后
如果您有一些有问题的组件,则始终可以使用以下方法使它的使用更加健壮:
创建一个进程(EXE),它封装了该组件的使用并公开了一个API (例如,通过任何IPC机制)。然后,您可以将该EXE作为一个单独的进程(从您的主EXE)开始,并使用它.如果您需要在某一时间和/或当满足某些条件时杀死该组件,则可以从您的主EXE中始终杀死该“包装器EXE”.根据特定组件的不同,在“包装器EXE”中实现一些特殊的“清理代码”(可能是在一个单独的线程中)可能是有用的,当您需要杀死该“包装EXE”时,该代码将被执行。
由于您是在.NET中实现这一功能,您甚至可以在主可执行文件中将“包装器EXE”作为“嵌入式资源”,甚至可以在不将其写入文件系统的情况下从RAM启动它.
发布于 2012-04-25 18:30:31
第三方DLL内部存在某种不确定的等待、循环或死锁。试图像这样绕过它是行不通的。您可能已经将挂起的调用分配给了一个工作线程,但是这个线程并没有消失,它一直挂在那个调用中。
下一次对COM组件的调用很可能是因为上一次冻结了。也许它是在尝试获得一把锁,而前一把锁是在上吊前获得的。也可能是因为同样的原因,而不是依赖的原因。
最好与第三方的开发人员/供应商联系,询问他们是否在某种程度上滥用它。有没有什么缺失的前提条件。一些未执行的初始化。一些必要的配置等。
https://stackoverflow.com/questions/10321504
复制相似问题