Уничтожить неуправляемые ресурсы в потоке - PullRequest
2 голосов
/ 16 марта 2012

У меня есть класс, который использует неуправляемые ресурсы в потоке, он также может перейти в спящий режим, когда он не используется.Я реализую утилизацию для этого, пожалуйста, посмотрите пример кода ниже (отмечая, что это дурацкая версия моего приложения).Я добавил while (TheThread.IsAlive ());как можно утилизировать можно установить в true до выполнения DestroySomeUnmangedResouces ().Я не думаю, что то, что я сделал, правильно, поэтому был бы признателен, если бы кто-то мог предложить лучшую модель.

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 ]

2 голосов
/ 16 марта 2012

Похоже, вы хотите дождаться завершения рабочего потока.Для этого вы можете просто использовать Thread.Join (), который будет блокироваться до тех пор, пока ваш поток не выйдет.

В настоящее время вы потребляете 100% ЦП в потоке ожидания, потому что вы делаете опрос, если рабочий поток еще жив.Менее ресурсоемкий вариант - ограниченный опрос, когда вы спите между своими проверками, по крайней мере, с временным интервалом (15 мс).

Но самый лучший подход - это ждать примитива синхронизации, который получает сигнал и пробуждает ваш потоккогда условие становится правдой.Следовательно, Thead.Join - это путь.

1 голос
/ 16 марта 2012

Вызывающий вызов dispose должен очистить поток - лучший способ - вызвать Join, как и предложил Alois.Как только поток присоединился, вы можете уничтожить неуправляемые ресурсы, которые теперь будут происходить в потоке вызывающих.Например:

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

Одним из недостатков этого подхода является то, что мы предполагаем, что поток в конечном итоге завершится.Он может зависнуть, означая, что сигналов для остановки потока было недостаточно.Для присоединения существует перегрузок , которые включают тайм-ауты, которые можно использовать для предотвращения зависания вызывающего потока (см. Комментарий в примере кода выше).

1 голос
/ 16 марта 2012
    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, если ваш поток не является фоновым

0 голосов
/ 17 марта 2012

Если работающий поток содержит прямую или косвенную сильную ссылку на объект, такая ссылка не позволит объекту получить право на сборку мусора. Таким образом, на самом деле нет никакой причины иметь финализатор для такого объекта.

Однако, если поток будет релевантным только до тех пор, пока ссылка на какой-то другой конкретный объект удерживается чем-то отличным от потока, может быть полезно, чтобы поток содержал WeakReference к этому другому объекту, и закройте себя, если тот другой объект выходит из области видимости. Это завершение может быть выполнено либо с помощью периодической проверки потока IsAlive свойством WeakReference, либо с помощью другого объекта, включающего финализатор, который будет сигнализировать отключению потока. Хотя периодический опрос для таких вещей в некотором смысле странен, и использование финализатора может несколько ускорить отключение потока, я думаю, что опрос, вероятно, все еще лучше. Хотя финализатор может уведомить поток о том, что он должен что-то сделать, и бывают случаи, когда это может быть уместно, в целом тот факт, что объект был завершен, означал, что никто не был чрезмерно обеспокоен быстрой очисткой. Добавление задержки еще на несколько секунд до отключения потока, вероятно, не повредит.

...