Финализатор выбрасывает случайные исключения, вызывает случайные ошибки, зависает приложение - PullRequest
0 голосов
/ 29 декабря 2011

У меня есть класс в C ++ / CLI, который использует неуправляемые ресурсы (HANDLE для собственного потока (т. Е. Из CreateThread ()) и LPVOID для волокна из CreateFiber / ConvertThreadToFiber).

По совету, который я получил от MSDN Я очищаю неуправляемые ресурсы в финализаторе (! Fiber ()), а деструктор (~ Fiber ()) вызывает финализатор.

Вот код:

Fiber::~Fiber () {

    this->!Fiber();

}


Fiber::!Fiber () {

    if (thread!=NULL) {

        delete thread;
        thread=NULL;

    }

    if (fiber!=NULL) {

        DeleteFiber(fiber);
        fiber=NULL;

    }

}

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

Unhandled Exception: System.AccessViolationException: Attempted to read or write
 protected memory. This is often an indication that other memory is corrupt.
   at DeleteFiber(Void* )
   at System.Threading.Fiber.!Fiber()
   at System.Threading.Fiber.Dispose(Boolean )
   at System.Threading.Fiber.Finalize()

Эта ошибка также может быть из строки:

delete thread;

А также.

Может также произойти сбой с OutOfMemoryException или зависанием на некоторое время, сказав, что программа переполнилась стеком, а затем повесив консоль (мне нужно закрыть cmd.exe и перезапустить его для восстановления).

Если я комментирую деструктор / финализатор и запускаю программу, она работает отлично, но это не вариант, потому что я не хочу, чтобы неуправляемые ресурсы зависали до тех пор, пока программа не закончится ...

1 Ответ

1 голос
/ 29 декабря 2011
  1. Если thread является HANDLE, вы очищаете его с CloseHandle(thread), а не delete thread.
  2. Вы должны инициализировать thread и fiber в NULL в конструкторе Fiber, чтобы поддерживать инварианты класса.
  3. Вы не можете вызвать DeleteFiberна текущем выполняемом волокне, если вы не хотите завершить поток.Вы убираете это, звоня ConvertFiberToThread()
...