Нельзя установить FreeOnTerminate
на True
и , вызвать Free
в экземпляре потока. Вы должны сделать одно или другое, но не оба. В таком виде ваш код уничтожает поток дважды. Вы никогда не должны уничтожать объект дважды и, конечно же, когда деструктор запускается во второй раз, возникают ошибки.
В данном случае происходит то, что, поскольку вы создали приостановленный поток, ничего не произойдет, пока вы явно не освободите поток. Когда вы это сделаете, деструктор возобновляет поток, ожидает его завершения. Это приводит к повторному вызову Free
, потому что для FreeOnTerminate
установлено значение True
. Этот второй вызов Free
закрывает дескриптор. Затем вы возвращаетесь в процесс потока, и он вызывает ExitThread
. Это не удалось, потому что дескриптор потока был закрыт.
Как отмечает Мартин в комментарии, вы не должны создавать TThread
напрямую, поскольку метод TThread.Execute
является абстрактным. Кроме того, вы не должны использовать Resume
, который устарел. Используйте Start
, чтобы начать выполнение приостановленного потока.
Лично я не люблю использовать FreeOnTerminate
. Использование этой функции приводит к удалению потока в другом потоке, из которого он был создан. Вы обычно используете его, когда хотите забыть о ссылке на экземпляр. Тогда вы не будете уверены в том, был ли поток уничтожен после завершения вашего процесса, или даже если он завершается и освобождается во время завершения процесса.
Если вы должны использовать FreeOnTerminate
, вам необходимо убедиться, что вы не звоните Free
после того, как для FreeOnTerminate
установлено значение True
. Таким образом, очевидное решение состоит в том, чтобы установить FreeOnTerminate
в True
непосредственно после вызова Start
и затем забыть об экземпляре потока. Если у вас есть какие-либо исключения до того, как вы будете готовы к запуску, тогда вы можете безопасно освободить поток, так как вы FreeOnTerminate
все равно будете False
на этом этапе.
Thread := TMyThread.Create(True);
Try
//initialise thread object
Except
Thread.Free;
raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
Более элегантный подход - перенести всю инициализацию в конструктор TMyThread
. Тогда код будет выглядеть так:
Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;