检测时,一个COM对象超出范围的 [英] Detect when a COM Object goes out of Scope

查看:90
本文介绍了检测时,一个COM对象超出范围的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个被暴露在COM .NET组件。

这部分具有内部运行的线程连接到一个命名管道,并处理从管道断开,并根据需要重新连接。

的线程运行的组件被实例化的程序的COM(维生素B6在本例中)内的实例的生命周期。

如果在COM应用程序正在关闭,但不叫我的关闭方法,它优雅地关闭线程(和管道),有没有一种方法来检测,他们正在关闭应用程序下来,这样我就不需要依靠他们正确地遵守规则?

线程都有它的IsBackground = true设置。

这是我的线程的基本组成部分。

 私人System.IO.Pipes.NamedPipeClientStream mPipe;
私人System.Threading.AutoResetEvent mConnectedHold;

私人无效ConnectPipe()
{
    而(mRunning)
    {
        尝试
        {
            mConnecting =真;
            mConnected = FALSE;
            如果(mPipe!= NULL)
            {
                mPipe.Close();
                mPipe.Dispose();
            }
            mPipe =新System.IO.Pipes.NamedPipeClientStream(@,@MyPipe,System.IO.Pipes.PipeDirection.InOut,System.IO.Pipes.PipeOptions.Asynchronous。);
            mPipe.Connect(1000);

            mConnecting = FALSE;
            mConnected =真;

            mPipe.BeginRead(mBuffer,0,mBuffer.Length,新的AsyncCallback(ReadPipe),NULL);

            mConnectedHold.WaitOne();
        }
        赶上(TimeoutException异常前)
        {
        System.Diagnostics.Debug.Print(尚未连接);
        }
        赶上(例外前)
        {
            mRunning = FALSE;
        }
    }
}
 

和关闭操作是非常基本的。

 公共无效关闭()
{
    mRunning = FALSE;
    如果(mPipe!= NULL)
    {
        mPipe.Close()
        mPipe.Dispose()
    }
    mConnected = FALSE;
}
 

解决方案
  

线程都有它的IsBackground = true设置。

COM不知道你的线程,VB6特别是因为它不支持线程在所有事情。在Thread.IsBackground属性设置为true告诉,这是正常中止线程,当程序的主线程退出的CLR。所以看到它突然终止,没有诊断是不足为奇的。

有一个与你的mRunning变量可能出现的问题,它需要申报的挥发性的。您在线程中使用它的方式很可能使这永远不会看到一个变化,在发布版本中的变量。抖动优化易于优化code和加载变量值在CPU寄存器。在挥发性的关键字prevents这一点。

这仍然是一个半生不熟的解决方案,你真的应该使用的ManualResetEvent信号线。调用它的设置()在你的Close()方法方法了WaitOne(0)在线程对其进行测试。然后,你还必须等待线程退出,使处置管道不弹线code。当心僵局。

现在你不需要Thread.IsBackground了,并得到了更好的机会,在调试这个code。你需要做的下一件事就是实现IDisposable,写一个终结你的类,以确保您的code正常关机,即使客户端code没有调用Close()方法很好。从刚才忘了这样做短,这也是必要的,如果客户端code轰炸。让你的Close()方法调用Dispose()。您可能需要做两件不同的事情取决于是否以正常方式应用程序关闭管道。落实处置模式,你可以告诉一个'好'关机之间(关闭被称为)(终结被称为)通过差与一个讨厌的一个的实施优化配置的说法。

现在你code是弹性的两种方式。找出为什么客户端code没有调用Close()应该很简单。

I have a .NET Component that is being exposed to COM.

This component has a thread running internally that connects to a named pipe, and handles disconnects from the pipe and reconnects as needed.

The thread runs for the lifetime of the instance of the component that was instantiated inside the COM Program (vb6 in this instance).

If the COM application is shutting down, but not calling my "Close" method that gracefully shuts down the thread (and pipe), is there a way to detect that they are closing the application down so that I do not need to rely on them following the rules properly?

The thread has it's ISBackground = true set.

This is the basic parts of my Thread

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;
        }
    }
}

and the close is fairly basic.

public void Close()
{
    mRunning = false;
    if (mPipe != null )
    {
        mPipe.Close()
        mPipe.Dispose()
    }
    mConnected = false;
}

解决方案

The thread has it's ISBackground = true set.

COM doesn't know anything about your thread, VB6 especially since it doesn't support threading at all. Setting the Thread.IsBackground property to true tells the CLR that it is okay to abort the thread when the program's main thread exits. So seeing it terminated abruptly without a diagnostic is unsurprising.

There's a likely problem with your mRunning variable, it needs to be declared volatile. The way you use it in your thread makes it likely that it never sees a change to the variable in the Release build. The jitter optimizer is liable to optimize the code and load the variable value in a CPU register. The volatile keyword prevents this.

This is still a half-baked solution, you really ought to use a ManualResetEvent to signal the thread. Call its Set() method in your Close() method, WaitOne(0) in the thread to test it. You then also have to wait for the thread to exit so that disposing the pipe doesn't bomb the thread code. Watch out for deadlock.

Now you don't need Thread.IsBackground anymore and got a better shot at debugging this code. Next thing you need to do is implement IDisposable and write a finalizer for your class to ensure that your code shuts down properly even if the client code didn't call the Close() method nicely. Short from just forgetting to do so, this is also necessary if the client code bombed. Have your Close() method call Dispose(). You might want to do two different things with the pipe depending on whether the app shutdown in a normal way. Implement the Disposing pattern, you can tell the difference between a 'nice' shutdown (Close was called) versus a nasty one (the finalizer was called) through the disposing argument.

Now your code is resilient either way. Finding out why the client code didn't call Close() should be simple.

这篇关于检测时,一个COM对象超出范围的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆