Вы не можете установить FreeOnTerminate
в True
и вызов Free
на экземпляре потока. Вы должны делать то или другое, но не то, и другое. В этом случае ваш код дважды разрушает поток. Вы никогда не должны разрушать объект дважды и, конечно, когда деструктор работает во второй раз, возникают ошибки.
Что происходит, так как вы создали приостановленную нить, ничего не происходит, пока вы явно не освободите поток. Когда вы это сделаете, деструктор возобновит поток, ждет его завершения. Это приводит к тому, что вызывается Free
, потому что вы установили FreeOnTerminate
в True
. Этот второй вызов Free
закрывает ручку. Затем вы возвращаетесь к потоку proc и звоните 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;
Во-первых, вы получаете какие-либо ошибки/предупреждения для этого? TThread.Execute является абстрактным в D2009. IME, вы должны получить предупреждение о создании экземпляров с абстрактными методами. Обычно TThread.Execute переопределяется в классе потомков TThread, и это потомок, который создается экземпляром. Я никогда не пытался создать экземпляр TThread напрямую - я уверен, что какое-то исключение будет поднято в потоке конструирования, построенном потоке или обоим. –
Вы можете подождать, чтобы установить 'FreeOnTerminate' до того, как вы назовете' Resume'. –
Я думаю, что уничтожить вызовы возобновить, потому что если поток был приостановлен, он не может быть правильно уничтожен в таком состоянии. –