Non è possibile impostare FreeOnTerminate
-True
e chiamata Free
sull'istanza thread. Devi fare l'uno o l'altro, ma non entrambi. Così com'è, il tuo codice distrugge la discussione due volte. Non devi mai distruggere un oggetto due volte e, naturalmente, quando il distruttore viene eseguito per la seconda volta, si verificano degli errori.
Quello che succede qui è che da quando hai creato il thread sospeso, non succede nulla fino a quando non liberi esplicitamente il thread. Quando lo fai, il distruttore riprende il thread, aspetta che si completi. Ciò quindi restituisce Free
che si chiama nuovamente perché imposta FreeOnTerminate
a True
. Questa seconda chiamata a Free
chiude l'handle. Quindi si ritorna al proc di thread e che chiama ExitThread
. Ciò non riesce perché l'handle del thread è stato chiuso.
Come Martin sottolinea nel commento non è necessario creare TThread
direttamente dal momento che il metodo TThread.Execute
è astratto. Inoltre, non dovresti usare Resume
che è deprecato. Utilizzare Start
per iniziare l'esecuzione di un thread sospeso.
Personalmente non mi piace usare FreeOnTerminate
. L'utilizzo di questa funzione comporta la distruzione del thread su un thread diverso da quello in cui è stato creato. Generalmente lo usi quando vuoi dimenticare il riferimento all'istanza. Questo ti lascia incerto sul fatto che il thread sia stato distrutto o meno al termine del tuo processo, o anche se si stia chiudendo e liberandosi durante la chiusura del processo.
Se è necessario utilizzare FreeOnTerminate
, è necessario assicurarsi di non chiamare Free
dopo aver impostato FreeOnTerminate
su True
. Quindi la soluzione più ovvia è impostare FreeOnTerminate
su True
immediatamente dopo aver chiamato Start
e poi dimenticare l'istanza di thread. Se hai qualche eccezione prima che tu sia pronto per iniziare, puoi tranquillamente liberare il thread, dal momento che lo FreeOnTerminate
sarebbe ancora False
a quel punto.
Thread := TMyThread.Create(True);
Try
//initialise thread object
Except
Thread.Free;
raise;
End;
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
Un approccio più elegante sarebbe quella di spostare tutti l'inizializzazione nel costruttore TMyThread
. Quindi il codice sarebbe simile a questo:
Thread := TMyThread.Create(True);
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil;
fonte
2012-01-10 15:44:47
In primo luogo, stai ricevendo errori/avvisi per questo? TThread.Execute è astratto in D2009. IME, dovresti ricevere un avvertimento sulla costruzione di istanze con metodi astratti. Normalmente, TThread.Execute viene sovrascritto in una classe discendente TThread ed è il discendente che viene istanziato. Non ho mai provato a creare direttamente un'istanza di TThread - Sono abbastanza sicuro che alcune eccezioni verrebbero sollevate sul thread di costruzione, sul thread costruito o su entrambi. –
Si può aspettare di impostare 'FreeOnTerminate' fino a poco prima di chiamare' Resume'. –
Immagino che distruggere le chiamate riprendere perché se un thread è stato sospeso non può essere distrutto correttamente in tale stato. –