Рассмотрим следующий фрагмент кода C ++ / CLI:
public ref class MyData
{
private:
UnmanagedObject* pobj;
public:
MyData()
{
pobj = ... // acquire unmanaged pointer
}
!MyData()
{
delete pobj; // finalizer
pobj = NULL;
}
void DoSomething()
{
// next line calls a native method that has no knowledge of .NET
CallToNativeMethod(data->pobj);
}
static void Test()
{
MyData^ data = gcnew MyData();
data->DoSomething()
}
}
Этот класс представляет собой .NET-оболочку для некоторого неуправляемого API.В моем проекте я в настоящее время имею дело с трудной для отслеживания ошибкой - кажется, что MyData
собирает мусор, пока метод DoSomething()
все еще выполняется.Вот что, я считаю, происходит:
- Вызывается статический метод
Test()
, который создает экземпляр MyData
- Метод экземпляра
DoSomething()
называется DoSomething()
вызывает собственный метод - Пока (!) Выполняется собственный метод, сборщик мусора собирает экземпляр
MyData
и вызывает финализатор - Финализатор удаляет
pobj
, который используется нативным методом , который все еще выполняется - Ну ... программа вылетает
Мои два вопроса:
- Возможен ли описанный выше сценарий на самом деле?Я не могу смириться с тем фактом, что объект может быть завершен, пока метод экземпляра все еще выполняется ...
- Какой хороший способ решить эту проблему (т.е. предотвратить сбор объекта)пока это "безопасно" сделать)?Изменение любой переменной экземпляра после , выполненного нативным методом, делает свое дело, но кажется, что это нереально.
EDIT (некоторыедополнительная информация): код падает с AccessViolationException
, который всплывает из нативного метода, и может быть пойман с помощью try..catch
в Test()
.Для отладки я вставил пару вызовов регистрации, которые показывают следующий порядок выполнения:
- Введен собственный метод (но никогда не завершен)
- Финализатор выполнен
- Исключение поймано