我有一个暴露给COM的.NET组件。
此组件在内部运行一个连接到命名管道的线程,并处理与管道的断开连接并根据需要重新连接。
线程运行在COM程序中实例化的组件实例的生命周期(在本例中为vb6)。
如果COM应用程序正在关闭,但没有调用我正好关闭线程(和管道)的“关闭”方法,有没有办法检测到他们正在关闭应用程序,这样我就不需要依靠他们正确遵守规则?
线程有ISBackground = true set。
这是我的线程的基本部分
private System.IO.Pipes.NamedPipeClientStream mPipe;
private System.Threading.AutoResetEvent mConnectedHold;
private void ConnectPipe()
{
while (mRunning)
{
try
{
mConnecting = true;
mConnected = false;
if (mPipe != null)
{
mPipe.Close();
mPipe.Dispose();
}
mPipe = new System.IO.Pipes.NamedPipeClientStream(@".", @"MyPipe", System.IO.Pipes.PipeDirection.InOut, System.IO.Pipes.PipeOptions.Asynchronous);
mPipe.Connect(1000);
mConnecting = false;
mConnected = true;
mPipe.BeginRead(mBuffer, 0, mBuffer.Length, new AsyncCallback(ReadPipe), null);
mConnectedHold.WaitOne();
}
catch (TimeoutException ex)
{
System.Diagnostics.Debug.Print("Not connected yet");
}
catch (Exception ex)
{
mRunning = false;
}
}
}
并且收盘相当基本。
public void Close()
{
mRunning = false;
if (mPipe != null )
{
mPipe.Close()
mPipe.Dispose()
}
mConnected = false;
}
答案 0 :(得分:1)
线程有ISBackground = true set。
COM对你的线程VB6一无所知,特别是因为它根本不支持线程。将Thread.IsBackground属性设置为true告诉CLR可以在程序的主线程退出时中止线程。因此,看到它在没有诊断的情况下突然终止并不足为奇。
您的mRunning变量可能存在问题,需要将其声明为 volatile 。在线程中使用它的方式使得它可能永远不会在Release版本中看到对变量的更改。抖动优化器可以优化代码并将变量值加载到CPU寄存器中。 volatile 关键字会阻止此操作。
这仍然是一个半生不熟的解决方案,你真的应该使用ManualResetEvent来通知线程。在Close()方法中调用其Set()方法,在线程中调用WaitOne(0)来测试它。然后你还必须等待线程退出,以便处理管道不会轰炸线程代码。注意僵局。
现在你不再需要Thread.IsBackground了,并且更好地调试了这段代码。接下来你需要做的是实现IDisposable并为你的类编写一个终结器,以确保你的代码正确关闭,即使客户端代码没有很好地调用Close()方法。如果忘记这样做,如果客户端代码被轰炸,这也是必要的。让Close()方法调用Dispose()。您可能希望使用管道执行两项不同的操作,具体取决于应用程序是否以正常方式关闭。实现Disposing模式,您可以通过 disposing 参数来区分“nice”关闭(Close被调用)与讨厌的(调用finalizer)之间的区别。
现在你的代码都有弹性。找出客户端代码没有调用Close()的原因应该很简单。
答案 1 :(得分:0)
也许使用其中一个AppDomain events。 “DomainUnload”和“ProcessExit”看起来很不错。
实际上,即使COM应用程序出现故障,您仍然希望托管代码保持运行。也许然后更改你的WaitOne以使TimeSpan参数定期唤醒,并测试客户端COM应用程序是否仍在那里。
答案 2 :(得分:0)
前一段时间我对它进行了调查,得出的结论是,无法检测何时释放.Net COM对象。
我发现最接近的是试图通过改变CCW的vtable来替换IUnknown.Release方法的人(Marshal类中有一些方法可以让你做这些事情)。有一些我不记得的严重问题。
您只需要构建您的类,以便它可以使用内部引用计数和终结器来处理这种情况。
对我来说,COM互操作不允许你添加某种OnFinalRelease事件似乎很奇怪。