在线程中处理非托管资源

时间:2012-03-16 14:47:37

标签: c# multithreading dispose

我有一个在线程中使用非托管资源的类,它也可以在不使用时进入休眠状态。我正在为它实现dispose,请参阅下面的示例代码(注意它是我的应用程序的一个愚蠢的版本)。我添加了(TheThread.IsAlive());在DestroySomeUnmangedResouces()执行之前,dispos可以设置为true。我不认为我所做的是正确的,所以如果有人能提出更好的模型,我将不胜感激。

protected virtual void Dispose(bool disposing)
{
    if (!disposed)
    {
        if (disposing)
        {   
            //managed
        }

        //unmanged
        _stopTheThread = true;
        startTheThreadEvent.Set();
        while(TheThread.IsAlive());
    }
    disposed = true;
}

private void TheThread()
{
    while (!_stopTheThread)
    {
        if (state == State.Stopped)
        {
            // wait till a start occurs
            startTheThreadEvent.WaitOne();
        }
        switch (state)
        {
            case Init: 
                CreateSomeUnmangedResouces();
                break;

            case Run:       
                DoStuffWithUnmangedResouces();
                break;

            case Stop:
                DestroySomeUnmangedResouces();
                break;
        } // switch
    }
    // Release unmanaged resources when component is disposed
    DestroySomeUnmangedResouces();
}

4 个答案:

答案 0 :(得分:2)

您似乎想等到工作线程退出。为此,您可以简单地使用Thread.Join(),它将阻塞直到您的线程退出。

目前,您正在等待线程上占用100%的CPU,因为如果工作线程仍处于活动状态,则会进行轮询。资源消耗较少的变体是一种限制性轮询,您可以在支票之间至少休息一次(15ms)。

但是迄今为止最好的方法是等待一个同步原语,当条件变为真时,该原语会发出信号并唤醒你的线程。因此,Thead.Join是要走的路。

答案 1 :(得分:1)

    private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
    private readonly ManualResetEvent _threadStoppedEvent = new ManualResetEvent(false);
    private bool disposed;
    private int checkInterval = 10;//ms


    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //managed
            }

            //unmanged
            _stopEvent.Set();
            _threadStoppedEvent.WaitOne();
        }
        disposed = true;
    }

    private void TheThread()
    {
        CreateSomeUnmangedResouces();

        while (!_stopEvent.WaitOne(checkInterval))
        { 
            DoStuffWithUnmangedResouces();   
        }

        DestroySomeUnmangedResouces();

        _threadStoppedEvent.Set();
    }

如果您的主题不是背景,您可以使用Thread.Join()而不是_threadStoppedEvent

答案 2 :(得分:1)

调用者调用dispose应该删除线程 - 最好的方法是按照Alois的建议调用Join。一旦线程加入,那么你可以销毁现在将在调用者线程上发生的非托管资源。 E.g:

    protected virtual void
    Dispose
        (bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                if(TheThread != null)
                {
                    // send a signal to stop the thread.
                    _stopTheThread = true;
                    startTheThreadEvent.Set();  

                    // Join the thread - we could timeout here but it should be the
                    // responsibility of the thread owner to ensure it exits
                    // If this is hanging then the owning object hasn't terminated
                    // its thread
                    TheThread.Join();

                    TheThread = null;
                }
            }

            // Now deal with unmanaged resources!
            DestroySomeUnmangedResouces();
        }

        disposed = true;
    }

这种方法的一个缺点是我们假设线程最终会退出。它可以挂起,意味着停止线程的信号是不够的。 Join有overloads,其中包括超时,可用于防止挂起调用线程(请参阅上面的代码示例中的注释)。

答案 3 :(得分:0)

如果正在运行的线程持有对象的直接或间接强引用,则此引用将阻止该对象符合垃圾回收的条件。因此,没有任何理由在这样的物体上设置终结器。

但是,如果该线程仅在引用某个其他特定对象由线程之外时才具有相关性,则该线程可能有用{{ 1}}到另一个对象,如果其他对象超出范围,则自行关闭。这种关闭可以通过让线程周期性地检查WeakReference的{​​{1}}属性,或者让另一个对象包含一个表示线程关闭的终结器来完成。虽然定期轮询这些东西在某种意义上是icky,并且使用终结器可以在一定程度上加快线程的关闭,我认为轮询可能仍然更好。尽管终结器可以通知线程它应该做某事,并且有时这样做可能是合适的,但一般来说,对象最终确定的事实意味着没有人过分担心及时清理。再加几秒钟'在线程关闭之前的延迟可能不会伤害任何事情。