Нарушение доступа к TThread при завершении / освобождении

#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 , что он уничтожит его правильно.