Как мне справиться с освобождением неуправляемых структур при закрытии приложения? - PullRequest
2 голосов
/ 14 мая 2010

У меня есть проект на C #, в котором я использую несколько неуправляемых функций C ++. Более того, у меня также есть статический IntPtr, который я использую в качестве параметров для этих функций. Я знаю, что всякий раз, когда я их использую, я должен реализовать IDisposable в этом классе и использовать деструктор для вызова метода Dispose, где я освобождаю используемый IntPtr, как сказано на странице MSDN.

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

private void Dispose(bool disposing)
{
    // Check to see if Dispose has already been called.
    if (!this.disposed)
    {
        if (disposing)
        {
            component.Dispose();
        }

        CloseHandle(m_InstanceHandle);
        m_InstanceHandle = IntPtr.Zero;

        disposed = true;

    }
}

[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);

Однако, когда я закрываю приложение, у меня все еще остается процесс зависания в TaskManager. Я считаю, что это должно быть связано с использованием инструкции MarshalAs в моих структурах:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
 public struct SipxAudioCodec
 {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
        public string CodecName;
        public SipxAudioBandwidth Bandwidth;
        public int PayloadType;
 }

Когда я создаю такую ​​структуру, я должен также быть осторожным, чтобы освободить место, которое она выделяет, используя деструктор?

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
 public struct SipxAudioCodec
 {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
        public string CodecName;
        public SipxAudioBandwidth Bandwidth;
        public int PayloadType;

        ~SipxAudioCodec()
        {
            Marshal.FreeGlobal(something...);
        }
 }

Ответы [ 2 ]

1 голос
/ 14 мая 2010

Правильный способ обработки дескрипторов IntPtr в стиле p / Invoke interop:

  • Определить класс SafeMyHandle, полученный из SafeHandle. Он должен только переопределять IsInvalid и ReleaseHandle и больше ничего не делать.
  • Определите другой класс MyHandle, который имеет методы для открытого API для этого дескриптора.
  • MyHandle должен иметь закрытый член типа SafeMyHandle.
  • MyHandle должен реализовывать IDisposable, а его метод Dispose должен просто вызывать SafeMyHandle.Dispose.
  • Все методы p / Invoke не должны использовать IntPtr напрямую; скорее они должны передать и вернуть экземпляры SafeMyHandle. Единственным исключением является «функция освобождения», которая вызывается из SafeMyHandle.ReleaseHandle; это должно занять IntPtr.

Если вы будете следовать этим соглашениям, ваши дескрипторы будут освобождены, даже если ваш домен приложений грубо разрушен.

0 голосов
/ 14 мая 2010

В прошлом у меня были случаи, когда приложение зависало после закрытия, обычно потому, что не все потоки были прерваны. Как вы закрываете свое приложение? Может быть, темы являются причиной?

...