Могу ли я использовать класс .NET SafeHandle и окончательно освободить дескриптор в нем? - PullRequest
1 голос
/ 28 января 2011

У меня есть проект .NET, в котором я извлекаю из ресурса во время выполнения и на основе разрядности платформы нативный код .DLL, который содержит функции, которые мне нужно использовать.Я использую LoadLibrary, GetProcAddress и FreeLibrary для управления загрузкой и использованием библиотеки в моем управляемом коде.

После того, как я закончу с нативной библиотекой, я бы хотел ее удалить.Вот некоторый псевдокод , показывающий рабочий процесс в том виде, в котором он реализован в данный момент:

internal class MyClass()
{    
    string nativeLibraryPath = "C:\my\path\to\extracted\library.dll";
    IntPtr nativeLibraryHandle = IntPtr.Zero;

    public void Load()
    {
        nativeLibraryHandle = NativeMethods.LoadLibrary(nativeLibraryPath);
    }

    public void ExecuteFunction()
    {
        IntPtr functionPointer = NativeMethods.GetProcAddress(nativeLibraryHandle, "MyFunctionName");
        // assume MyManagedDelegate is defined as the correct delegate type.
        MyManagedDelegate managedFunction = Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(MyManagedDelegate)) as MyManagedDelegate;
        managedFunction("foo", "bar");
    }

    public void Unload()
    {
        NativeMethods.FreeLibrary(nativeLibraryHandle);
        File.Delete(nativeLibraryPath);
    }
}

Это прекрасно работает при использовании переменных типа IntPtr.Преобладающая мудрость (лучшие практики?) Указывают на то, что SafeHandle может быть лучшим подходом.Тем не менее, я понимаю, что при использовании SafeHandle, метод ReleaseHandle () не вызывается детерминистически.То есть вызов метода Close () или Dispose () для SafeHandle только помечает класс для сборки мусора;он не вызывает ReleaseHandle, пока объект не будет собран.Это проблема для меня, потому что я не могу удалить свой собственный код .DLL, пока он не выгружен.Если я вызываю FreeLibrary во время ReleaseHandle, как я могу определенно ждать, пока библиотека выйдет (не прибегая к таким хакерским действиям, как вызов GC.Collect ())?

EDIT Я обновилпример, чтобы быть более представительным для того, как мой фактический код структурирован.Обратите внимание, что код, размещенный в этом примере, не является полным.Я включил необходимую проверку ошибок и обработку исключений в свой производственный код.

Ответы [ 2 ]

3 голосов
/ 28 января 2011

Нет, это не точно.SafeHandle заботится об освобождении дескриптора, когда ваш код забывает это сделать.Только , что будет происходить недетерминированно, код, который выполняется в потоке финализатора.Вызов Dispose () очень детерминирован.

Ваш код в том виде, в котором он написан, не безопасен, он будет постоянно пропускать дескриптор модуля при бомбардировке исключения.Вы должны использовать блок finally, чтобы гарантировать освобождение дескриптора.Что вполне достаточно, вам не нужен SafeHandle, поскольку вы сохраняете дескриптор как локальную переменную и всегда можете его детерминистически освободить.

2 голосов
/ 28 января 2011

Вы ошибаетесь.
Вызов Close() освободит дескриптор.

Однако он закроет дескриптор только тогда, когда его счетчик ссылок равен нулю (это поддерживается дескриптором; GC нене использовать ref-count)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...