#c #tthread
#c #tthread
Вопрос:
Я запускаю короткий фрагмент кода, который иногда (очень редко) нарушает доступ к завершению / освобождению моего TThread. Я запускаю много экземпляров этих потоков, но это место, похоже, единственное, которое вызывает проблемы, и оно делает это только один раз каждые 500 или около того вызовов.
TThreadInheritor* Base= new TThreadInheritor(1);
try {
Base->Start();
WaitForSingleObject((HANDLE)Base->Handle, 1000);
MyBaseId = Base->scanvalue;
}__finally {
Base->Terminate();
Base->Free();
}
Он выбрасывается в мой finally. Мое первое предположение заключалось в том, что WaitForSingleObject странным образом отключался и приводил к сбою Terminate и Free, но я не совсем уверен, как это произойдет. Я ничего не менял в методах Terminate / Free, когда я унаследовал от TThread.
Кто-нибудь знает, что может привести к тому, что эти два метода доступа будут нарушены после такого небольшого количества кода?
Комментарии:
1. Ну, вы, конечно, могли бы начать хотя бы с проверки возвращаемого значения
WaitForSingleObject
…
Ответ №1:
Никогда не освобождайте a TThread
, который все еще работает. Деструктор базового класса TThread
небезопасен в этом отношении. Он делает некоторые довольно глупые вещи, которые могут вызвать проблемы. ВСЕГДА убедитесь, что a TThread
полностью завершен, прежде чем освобождать его. Используйте WaitFor()
метод или дождитесь WaitForSingleObject()
отчетов WAIT_OBJECT_0
.
Комментарии:
1. Ну ладно. Я ошибочно предполагал, что завершение будет выполняться синхронно с вызывающим потоком.
Ответ №2:
Во-первых, не используйте Base->Free()
. Используйте delete Base;
вместо этого.
Что еще более важно, вы должны вызвать Base->WaitFor()
after Terminate()
, чтобы убедиться, что он действительно завершен до удаления объекта.
Base->Terminate();
Base->WaitFor();
delete Base;
В противном случае вы бы преждевременно удалили объект thread (который все еще может использоваться вашим кодом / RTL), что привело бы к случайному нарушению доступа.
Или вы можете установить FreeOnTerminate
для свойства значение true и вообще забыть об ожидании / удалении объекта (будьте осторожны с нехваткой виртуальной памяти, если у вас слишком много потоков, поскольку 64-разрядной версии C Builder еще нет).
Комментарии:
1. Почему я не должен вызывать base-> Free() ? Если это небезопасная функция, я бы предположил, что она не будет включена в класс.
2.
TThread
происходит отTObject
, который является классом Delphi с оболочкой совместимости на C .Free()
это методTObject
, поэтому он вообще существует в C , но на самом деле он используется только в Delphi. Его не следует использовать в C , вместо этого всегда сохраняйтеnew
иdelete
балансируйте в C . Компилятор знает, что класс основан на Delphi, и удостоверитсяdelete
, что он уничтожит его правильно.