我正在使用通过COM Interop包装器公开的第三方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就会调用它,以便我们可以适当地记录信息。但是,正如我所说的, ANY COM组件将在此等待时冻结(如果第三方锁定,我们自己锁定的自定义COM)
更新2
以上代码可以工作,并延迟UI线程的挂起,直到下一次COM调用。尝试解决此问题的原因是因为var deviceInfo = _myCom.get_DeviceInfo(0);
已经锁定了UI线程。但是,此信息并不重要,仅用于记录,因此这种方法允许“放弃并在15秒后继续”方案
这里的另一个解决方法是找到一种在x秒后取消COM调用的方法吗?
答案 0 :(得分:3)
更新 - 从OP的第二次更新
之后如果您有一些有问题的组件,您可以使用以下方法使您的使用更加健壮:
创建一个进程(EXE),它包装该组件的用法并公开API(例如通过任何IPC机制)。然后,您可以将EXE作为一个单独的进程(来自您的主EXE)启动并使用它...如果您需要在一定时间后杀死该组件和/或满足某些条件,您可以始终杀死“包装器EXE”来自你的主要EXE ......根据具体的组件,它甚至可能有助于在“包装器EXE”中实现一些特殊的“清理代码”(可能在一个单独的线程中),当你需要杀死那个“包装器EXE”时它会被执行”
由于您在.NET中实现此功能,您甚至可以将“wrapper EXE”作为“嵌入式资源”放在主可执行文件中,甚至可以从RAM启动它而无需将其写入文件系统...
答案 1 :(得分:1)
第三方DLL内部存在某种无限期的等待,循环或死锁。试图像这样解决它是行不通的。你可能已经对工作线程进行了挂起调用,但该线程并没有消失;它一直挂在那个电话里。
对COM组件的下一次调用最有可能冻结,因为前一个组件冻结了。也许它试图获得前一个在挂起之前获得的锁。或者它可能因为完全相同的原因而悬挂,而不是依赖原因。
更好地联系第三方的开发商/供应商,并询问他们是否以某种方式滥用它。是否有一些缺失的前提条件。一些未执行的初始化。一些必要的配置等。