2010-05-04 18 views

risposta

13

(Semplificazione avanti)

Un thread UI è un singolo Threading Apartment filo che viene utilizzato per creare vari oggetti dell'interfaccia utente (in WinForms, questo significa controlli). Per convenzione e regola, un controllo può solo accessibile dal thread utilizzato per crearlo; fare altrimenti può e produrrà risultati inaspettati, dalle stranezze visive fino ad un crash.

A meno che non si crei di più in modo esplicito, esiste solo un thread dell'interfaccia utente all'interno di un'applicazione Windows Form. Mentre tu puoi creare un altro thread e avviare un loop di messaggi, ci sono pochissimi motivi per cui vorresti farlo e due diversi thread UI non possono "dialogare" l'un l'altro più di quanto qualsiasi altro thread possa parlare ad un altro Thread dell'interfaccia utente.

+2

+1 per aver menzionato che puoi farlo, ma che raramente è il modo in cui le cose dovrebbero essere fatte ... –

+0

Allora, cosa succede quando fai un nuovo Thread(). Start() all'interno di un STAThread? –

+0

@Griever: inizia un nuovo thread, ma è completamente separato dal thread dell'interfaccia utente. L'esecuzione di una nuova discussione inizia ovunque crea una nuova discussione non correlata. –

0

CURA per la correttezza:

C'è un thread UI per ogni applicazione attiva in Windows Form e concetto simile per WPF.

es .: quando si avvia l'applicazione, c'è un thread, diventa un thread dell'interfaccia utente quando Application.Run (new Form1()); è chiamato.

Se si tenta di eseguire Application.Run (new Form2()); in fase di esecuzione verrà visualizzato "System.InvalidOperationException: l'avvio di un secondo ciclo di messaggi su un singolo thread non è un'operazione valida." Utilizzare invece Form.ShowDialog. "

Se realmente avevi bisogno di due moduli separati per non condividere lo stesso thread, dovresti creare un nuovo thread, quindi chiamare Application.Run (new MyForm()) ecc. Ecc. Questo non è comune.

+1

Questo non è vero. Moduli diversi, in Windows Form, utilizzano tutti lo stesso ** thread. Il messaggio pompa li rende tutti reattivi. –

+0

L'ho invertito, le finestre di dialogo modali richiedono un nuovo thread, le finestre di dialogo non modali non richiedono * un nuovo thread. Il punto è che i normali thread possono diventare thread ui quando viene lanciato un nuovo modulo. – David

+0

Questo è ancora falso. "Avviare un modulo" da un nuovo thread, senza un'attenzione particolare per avviare un loop di messaggi, causerà tutti i tipi di problemi, incluso (nella maggior parte dei casi) l'arresto anomalo a causa della mancanza di STA per impostazione predefinita. –

7

thread A UI ha una serie di caratteristiche che lo rendono speciale:

  • Windows ha una coda di messaggi associato al thread. Questo succede non appena viene creata la prima finestra sul thread.
  • Il thread esegue un ciclo di messaggi, consentendo a Windows di inviare messaggi alle finestre. Il ciclo dei messaggi viene creato non appena si chiama Application.Run().
  • COM è stato inizializzato sul thread, richiedendo un apartment a thread singolo. Uno STA è necessario per consentire a molte funzionalità di Windows di funzionare correttamente, funzionalità che non sono sicure per i thread in base alla progettazione. COM garantisce che tali funzionalità vengano sempre richiamate in modalità thread-safe, eseguendo il marshalling della chiamata da un thread di lavoro sul thread STA secondo necessità. Esempi di queste funzionalità sono Drag + Drop, gli appunti, le finestre di dialogo della shell (OpenFileDialog ecc.), I controlli ActiveX come WebBrowser, gli hook della finestra impostati da SetWindowsHookEx, i provider di accessibilità come utilizzati da uno screen reader, i provider di automazione dell'interfaccia utente. Tutti i codici esterni, nessuno dei quali thread-safe.
  • Il thread non blocca mai alcuna operazione, rimane reattivo in modo che possa inviare messaggi Windows come richiesto per mantenere l'interfaccia utente reattiva e le richieste di marshalling COM scorrenti. Effettuare chiamate a WaitHandle.WaitAny() ad esempio è esplicitamente vietato e genera un'eccezione. Il CLR ha supporto specifico per WaitOne() e lock, pompando un loop di messaggi interno per evitare il deadlock.

Il thread di avvio di un processo è quasi sempre selezionato come thread dell'interfaccia utente, anche se non è un requisito difficile. Lo stato STA è selezionato dall'attributo [STAThread] sul metodo Main().

È possibile creare un thread dell'interfaccia utente assicurandosi che i requisiti precedenti siano soddisfatti. Questo potrebbe apparire come questo in un app WinForms:

var ui = new Thread(() => { Application.Run(new Form2()); }); 
    ui.SetApartmentState(ApartmentState.STA); 
    ui.Start(); 

che crea una seconda finestra, in esecuzione sul proprio thread UI. Un tipico problema che hai con questa disposizione è che ora hai due finestre separate, non sono affatto associate tra loro. La 2a finestra non può essere posseduta dal 1 °, ha il suo Z-order indipendente dal 1 °. Difficile da gestire da parte dell'utente. L'evento SystemEvents.UserPreferenceChanged è notevole, invierà inevitabilmente il suo evento sul thread sbagliato e questo è suscettibile di causare deadlock. Un sacco di controlli di WinForms lo sottoscrivono. Tranne che in rare circostanze, come una schermata iniziale, ciò non migliora affatto l'interfaccia utente.

+0

Mi piace la tua risposta dettagliata. –

Problemi correlati