2014-10-30 2 views
3

Вот пример, о котором я не уверен:Как правильно распоряжаться сбором неуправляемых ресурсов из финализатора?

public class SomeClass : IDisposable { 

    ~SomeClass() { 
     Dispose(false); 
    } 

    public void Dispose() { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    private bool _disposed; 

    protected virtual void Dispose(bool disposing) { 
     if (!_disposed) { 
      if (disposing) { 
       // TODO: Release any managed resources here... 
      } 

      // ?! Is it safe to enumerate the dictionary here ?! 
      foreach (var resource in _resources.Values) 
       ReleaseBuffer(resource); 
      _resources = null; 

      _disposed = true; 
     } 
    } 

    private Dictionary<string, IntPtr> _resources; 

    ... 

} 

Будет ли это безопасно перечислить управляемый словарь для того, чтобы освободить неуправляемые ресурсы?

Является ли наличие неопределенного словаря, поскольку порядок, в котором вызывается финализатор, не определен?

Вот цитата взята из MSDN, которую я считаю запутанным [1]:

  • В финализаторах двух объектов не гарантируют выполнение в любом определенном порядке, даже если один объект относится к Другие. То есть, если объект A имеет ссылку на объект B, и оба имеют финализаторы, объект B может быть уже завершен, когда начинается финализатор объекта A.
  1. http://msdn.microsoft.com/en-us/library/system.object.finalize(v=vs.110).aspx
+1

Должен быть безопасным, словарь - это управляемый объект, внедренный в экземпляр вашего класса, и он будет доступен до тех пор, пока не будет вызван финализатор. См. Http://stackoverflow.com/questions/13954829/gc-collect-and-finalize. – galenus

+2

'Словарь' не имеет финализатора. Так что ты в безопасности. – Blorgbeard

+2

@Blorgbeard: Словарь не является потокобезопасным, и ничего не гарантируется в контексте потоков, в котором запущен финализатор. – supercat

ответ

2

Вместо того, чтобы иметь словарь неуправляемых ресурсов, я бы предложил иметь словарь независимых объектов-оберток, каждый из которых несет ответственность за охрану одного неуправляемого ресурса. Если объект, содержащий словарь, оставлен, и никакие другие ссылки не существуют в объектах-оболочках, все объекты-обертки будут завершены без необходимости вовлечения самого словаря в этот процесс. Использование такого подхода облегчит безопасное обращение с случаями, в которых возникает исключение при построении объекта, и, по крайней мере, несколько разумно справляется с ситуациями, когда объект оказывается воскрешен между временем, когда он был установлен в очередь для финализации, и время, когда финализатор запускает [код, как правило, нельзя ожидать «правильно» в таких случаях, но должен избегать искажения состояния остальной системы].

Например, код, который использует дескриптор, может получить блокировку во время ее использования и после использования проверить флаг «disposeObjectASAP»; если установлено, повторно приобретите блокировку и удалите объект. Сам финализатор должен установить флаг, а затем попытаться получить блокировку; если он успешно получает блокировку, он должен уничтожить объект.Если не удается, тот факт, что он установил флаг, должен означать, что код, который имеет блокировку, предназначен для проверки флага и очистки объекта, поэтому финализатору этого не нужно. Если финализатор работает досрочно, он может освобождать ресурсы, для которых нужен другой поток, что приведет к сбою действий в этом другом потоке, но финализатор не будет освобождать ресурсы, пока другой поток использует их или удаляет их, поскольку освобождение ресурсов в этих ситуации могут вызвать массовое повреждение системы.

0

Согласно Implementing a Dispose method, код, который вы показать здесь не безопасно.

Пример кода показывает:

protected virtual void Dispose(bool disposing) 
{ 
    if (disposed) 
     return; 

    if (disposing) { 
     // Free any other managed objects here. 
     // 
    } 

    // Free any unmanaged objects here. 
    // 
    disposed = true; 
} 

Ваш пример показывает, освободив неуправляемых ресурсов в условном блоке. Пример MSDN показывает, что вы должны освободить ресурсы в условном блоке.

Как говорится в тексте (под заголовком, "The Dispose (Boolean) перегрузка"):

Если вызов метода происходит от финализации (то есть, если утилизации является false), только выполняется код, освобождающий неуправляемые ресурсы. Поскольку порядок, в котором сборщик мусора уничтожает управляемые объекты во время финализации, не определен, вызов этой Dispose перегрузки со значением false мешает финализатору попытаться освободить управляемые ресурсы, которые, возможно, уже были исправлены.

+0

Комментарий в моей инструкции 'if (disposing)' был чисто опечаткой. Но был предназначен доступ к коллекции '_resources'. Я исправил эту опечатку в моем вопросе для будущей ясности. благодаря –