2014-05-11 7 views
5

Lo so Synchronize deve essere utilizzato nella procedura Execute, ma dovrebbe essere utilizzato anche nei metodi Create e Destroy oppure è sicuro fare qualsiasi cosa io voglia?In quali metodi di thread dovrebbe essere utilizzato Synchronize?

+1

Non è necessario utilizzare 'Synchronize()' se non è necessario sincronizzare nulla. Anche se si dispone di un thread di calcolo che produce risultati che si desidera visualizzare "quando pronto": non è necessario chiamare direttamente "Synchronize()". Se usi l'evento 'OnTerminate', Delphi lo sincronizza già per te. –

+4

Come probabilmente si ottiene da altre risposte/commenti, il nome 'Synchronize()' viene in qualche modo scelto male. Dovrebbe davvero essere chiamato "ExecuteThisOnTheMainUIThread' perché questo è l'intero scopo: richiedere, all'interno del blocco Execute di un thread, che una parte di codice debba essere eseguita sul thread dell'interfaccia utente, consentendo così l'interazione con gli elementi dell'interfaccia utente. Tutto ciò che non ha bisogno di interagire con i controlli dell'interfaccia utente può essere eseguito all'interno del thread senza sincronizzazione con il thread dell'interfaccia utente. –

+1

@ 500-InternalServerError: accetta la tua affermazione sul nome sbagliato. Sfortunatamente cadi nella stessa trappola con la tua ultima frase - dovrebbe essere qualcosa come "senza passare al thread dell'interfaccia utente", perché la corretta * sincronizzazione * (con tutti i thread, non solo il thread dell'interfaccia utente) potrebbe essere effettivamente necessaria. – mghie

risposta

4

È necessario utilizzare Synchronize() quando il codice è in esecuzione al di fuori del contesto del thread principale (GUI) dell'applicazione. Quindi la risposta alla tua domanda dipende dal fatto che il costruttore e il distruttore siano chiamati da quel thread o meno.

Se non sei sicuro si può verificare che confrontando il risultato della funzione API di Windows GetCurrentThreadId() con la variabile MainThreadID - se eguagliare il codice viene eseguito nel contesto del thread principale.

I thread che hanno il set FreeOnTerminate avranno il loro distruttore chiamato da un altro contesto di thread, quindi sarà necessario utilizzare Synchronize() o Queue(). Oppure si utilizza l'evento di terminazione già fornito dal VCL, credo che sia eseguito nel thread principale, ma si controlli la documentazione per i dettagli.

8

I know Synchronize must be used in the Execute procedure.

che è un po vago. È necessario utilizzare Synchronize quando si dispone di codice che deve essere eseguito sul thread principale. Quindi la risposta alla necessità o meno di usare Synchronize dipende in modo cruciale da ciò che il codice in esame effettivamente fa. La domanda che devi porci e che è una che solo tu puoi rispondere è che hai un codice che deve essere eseguito sul thread principale?

Come regola generale, sarebbe consigliabile evitare di dover chiamare il Synchronize al di fuori del metodo Execute. Se riesci a trovare un modo per evitare di farlo, sarebbe saggio. Ricorda che lo scenario ideale con i thread è che non hanno mai bisogno di bloccare con Synchronize se possibile.


Si potrebbe anche voler considerare quale thread esegue il costruttore e il distruttore.

Il costruttore Create viene eseguito nel thread che lo chiama. Non viene eseguito nel thread appena creato. Pertanto è improbabile che sia necessario utilizzare Synchronize lì.

Il distruttore Destroy viene eseguito nella discussione che lo chiama. In genere questo è il thread che chiama Free sull'oggetto thread. E di solito questo sarebbe chiamato dallo stesso thread che originariamente ha creato il thread. L'eccezione comune a questo è una thread FreeOnTerminate che chiama Free dal thread.

5

Prima di tutto, non si desidera chiamare Synchronize() inutilmente, perché ciò vanifica semplicemente lo scopo di utilizzare un thread. Quindi la decisione dovrebbe essere basata sul fatto che: (a) è possibile riscontrare condizioni di gara con dati condivisi. (b) utilizzerai il codice VCL che di solito deve essere eseguito sul thread principale.

È improbabile che sia necessario eseguire la sincronizzazione nel costruttore poiché le istanze TThread vengono generalmente create già dal thread principale. (L'eccezione è se stai creando alcuni TThread da un altro thread figlio.)

NOTA: non causerà alcun danno, però, perché Synchronize() controlli già se siete sul thread principale e si chiama il metodo sincronizzato immediatamente se siete.

class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False); 
var 
    SyncProc: TSyncProc; 
    SyncProcPtr: PSyncProc; 
begin 
    if GetCurrentThreadID = MainThreadID then 
    ASyncRec.FMethod 

Per quanto riguarda il distruttore ci sono 3 modalità di utilizzo:

  • I TThread casi distrugge se stessa.
  • Un altro thread (probabilmente il thread principale) può WaitFor l'istanza da finire, quindi distruggerlo.
  • È possibile intercettare l'evento OnTerminate. Questo viene generato quando l'istanza è finita e tu potresti distruggerlo.

NOTA: L'evento OnTerminate sarà già sincronizzato.

procedure TThread.DoTerminate; 
begin 
    if Assigned(FOnTerminate) then Synchronize(CallOnTerminate); 
end; 

luce di quanto sopra, l'unica volta che potrebbe essere necessario per sincronizzare è se il filo si autodistrugge.

Tuttavia, ti consiglio di evitare di inserire il codice nel distruttore che potrebbe dover essere sincronizzato. Se hai bisogno di alcuni risultati di un calcolo dalla tua istanza di thread, OnTerminate è il posto più appropriato per ottenere questo.

4

da aggiungere a quanto è stato detto in altre risposte ...

Non si può mai necessità da usare Synchronize a tutti. Synchronize può essere utile, tuttavia, nella seguente circostanza:

  1. Nel contesto del tuo thread è necessario eseguire il codice che tocca oggetti che hanno affinità con il thread principale.
  2. È necessario bloccare il thread finché il codice non è stato eseguito.

Anche in questo caso, ci sono altri modi per raggiungere lo stesso obiettivo, ma Synchronize fornisce un modo conveniente per soddisfare queste due esigenze. Se hai bisogno solo di uno di questi due elementi, ci sono strategie migliori disponibili.

Sull'argomento n. 1, gli oggetti ovvi sono oggetti dell'interfaccia utente. Si tratta di oggetti che hanno affinità di thread con il thread principale semplicemente in virtù del fatto che il thread principale legge e scrive continuamente le proprietà di quegli oggetti (non ultimo perché ha bisogno di dipingerli sullo schermo, ecc.) E lo fa quindi a sua propria convenienza. Ciò significa che il thread non può accedere in modo sicuro a tali componenti con la garanzia che anche il thread principale non li accederà o li modificherà allo stesso tempo. Per prevenire la corruzione, il thread deve passare il lavoro al thread principale (dal momento che il thread principale può fare solo una cosa alla volta e non può, ovviamente, interferire con se stesso). Synchronize posiziona semplicemente il lavoro sulla coda del thread principale e attende fino a quando il thread principale non si avvicina al completamento prima di tornare.

Questo arriva al punto # 2. Hai bisogno di (o, allo stesso modo, puoi permetterti di) aspettare fino a quando il thread principale termina il lavoro?Ci sono tre casi e due opzioni.

  1. Sì, è possibile o deve attendere. (Synchronize è una buona misura)
  2. No, non puoi aspettare. (Synchronize non è una buona misura)
  3. Non importa. (Synchronize è facile, quindi è una scelta sensata)

Se si sta semplicemente aggiornando una visualizzazione di stato che sarà presto sovrascritto in ogni caso e la vostra discussione ha problemi più pressanti, allora è probabilmente sensato solo inviare un messaggio al filo principale e continua a fare cose, per esempio. Se il tuo thread è solo in attesa di non fare nulla, soprattutto, e non vale la pena di codificare qualcosa di più sofisticato, allora Synchronize va bene, e può essere sostituito con qualcosa di meglio se è necessario dettare così in futuro.

Come altri hanno già detto, dipende davvero da quello che stai facendo. La domanda più importante, secondo me, almeno concettualmente, è quella di risolvere quando è necessario preoccuparsi della concorrenza e quando non lo si fa. Ogni volta che si dispone di più thread che richiedono l'accesso a una singola risorsa, è necessario utilizzare una sorta di meccanismo per coordinare tale accesso per evitare che i thread si blocchino l'uno contro l'altro. Synchronize è uno di quei metodi, ma non il minimo né l'ultimo di essi.

Problemi correlati