2010-05-31 17 views
8

Quando si invia un messaggio "se la finestra specificata è stata creata dal thread chiamante, la procedura della finestra viene richiamata immediatamente come subroutine". Ma "se la finestra specificata è stata creata da un thread diverso, il sistema passa a quel thread e richiama la procedura di finestra appropriata.I messaggi inviati tra thread vengono elaborati solo quando il thread di ricezione esegue il codice di recupero dei messaggi" (preso da MSDN documentazione per SendMessage).Come viene eseguito SendMessage da un thread diverso?

Ora, non capisco come (o, più propriamente, quando) la procedura di Windows di destinazione si chiama. Ovviamente il thread di destinazione non verrà anticipato (il contatore del programma non viene modificato). Presumo che la chiamata avverrà durante alcune funzioni di attesa (come GetMessage o PeekMessage), è vero? Quel processo è documentato in dettaglio da qualche parte?


Aggiornamento: la logica dietro di esso si spiega con la QS_SENDMESSAGE bandiera di GetQueueStatus() e MsgWaitForMultipleObjects():

QS_SENDMESSAGE 
A message sent by another thread or application is in the queue. 

Questo, insieme con osservazioni aggiuntive nella documentazione MSDN, significa che un messaggio inviato da un altro thread è effettivamente pubblicato in coda. Quindi, non appena GetMessage o PeekMessage vengono chiamati, verrà elaborato prima di qualsiasi altro messaggio inviato per essere inviato direttamente alla procedura della finestra.

risposta

5

Qui vedo un po 'di confusione.

Secondo la documentazione MSDN, quando si tocca la coda di messaggi del thread corrente con l'intento di elaborazione dei messaggi (ad esempio, se si chiama PeekMessage o GetMessage), tutto in sospeso inviato (cioè non in attesa) messaggi da altri le discussioni sono gestite - passati al WndProc - e poi la coda di messaggi è selezionata, in modo da:

  • messaggi inviati mai passare attraverso DispatchMessage e sono curati al più presto possibile:
    • nel thread corrente, sono semplicemente passati al WndProc
    • in un altro thread, che vengono gestiti prima di qualsiasi elaborazione messaggio postato
  • per essere in grado di gestire i messaggi inviati, il thread di destinazione ha ancora bisogno di un pompa messaggio
  • PostThreadMessage fa proprio ciò che afferma - messaggi un messaggio in una coda di discussioni - tali messaggi non sono diretti a qualsiasi finestra e deve essere maneggiato explixitly
  • il solo messaggi gestiti da DispatchMessage sono quelli creati da PostMessage o qualche funzione di sistema (timer, eventi, input dell'utente, ecc)
  • evitare bloccaporte, utilizzare SendNotifyMessage, SendMessageTimeout o SendMessageCallback invece del semplice SendMessage tra i diversi fili

Per ulteriori informazioni, consultare la sezione Note della voce MSDN PeekMessage.

+0

Grazie, questo sicuramente risponde al mio dubbio. Sfortunatamente nella documentazione Get/PeekMessage di Windows CE 6 mancava quella parte nella sezione "Note" (mi chiedo se WinCE GWES abbia un comportamento leggermente diverso rispetto a USER Win32). – Wizard79

+4

La documentazione GetMessage dice che "invia i messaggi inviati in entrata fino a quando un messaggio inviato non è disponibile per il recupero." Ecco perché SendMessage dice "i messaggi inviati tra i thread vengono elaborati solo quando il thread ricevente esegue il codice di recupero dei messaggi". L'invio di un messaggio a un thread diverso richiede pertanto che il thread di destinazione abbia un loop di messaggi. L'invio di un messaggio sullo stesso thread comporta una chiamata alla procedura diretta della finestra sullo stesso thread. L'invio di un messaggio a un altro thread comporta una chiamata alla procedura diretta della finestra sul thread di destinazione * all'interno di una chiamata GetMessage *. – Triynko

+0

Ora, per quanto riguarda la priorità dei messaggi inviati e inviati, è molto chiaro. Se il loop del messaggio di destinazione è in attesa di messaggi da pubblicare (ovvero si blocca all'interno di una chiamata GetMessage), un messaggio inviato verrà elaborato per primo se arriva prima di un messaggio inviato. Se il loop del messaggio di destinazione sta effettivamente elaborando un messaggio (cioè chiama Translate o DispatchMessage), allora un messaggio inviato verrà elaborato prima di un messaggio inviato, anche se arriva più tardi, purché arrivi al momento in cui il loop del messaggio di destinazione termina l'elaborazione qualunque messaggio sia nel mezzo dell'elaborazione. – Triynko

1

Risposta breve: quando il thread di destinazione chiama GetMessage (o PeekMessage) seguito da DispatchMessage, il SendMessage dell'altro thread viene ricevuto e gestito.

Non sono sicuro che SendMessage ricevuto prevenga altri messaggi in coda oppure no. In entrambi i casi, un SendMessage da un thread all'altro è come dire: "Posta questo messaggio nella coda dei messaggi del secondo thread. Torna quando quel thread ha finito di elaborarlo".

Un ora una risposta che non ha chiesto:

In generale, quando programmo interazioni tra il thread UI principale e un thread di lavoro, cerco di evitare l'uso di SendMessage. Se non stai attento, puoi entrare in una situazione in cui entrambi i thread sono bloccati l'uno sull'altro. (Pensa al caso in cui il thread principale chiama WaitForSingleObject per attendere il completamento del thread worker, ma il thread worker è bloccato su SendMessage sul thread dell'interfaccia utente).

+0

OK, quindi fare SendMessage da un thread diverso (in realtà anche un processo diverso nel mio caso) è come utilizzare un "PostMessage di blocco"? Il mio problema è che devo creare un ciclo di messaggi secondario usando MsgWaitForMultipleObjectsEx e PeekMessage (su Windows CE). – Wizard79

+0

Non sei sicuro di cosa stai provando a fare, ma se è per le comunicazioni tra processi, allora dovresti usare COM. – selbie

+0

Devo risolvere alcuni limiti del sistema su cui sto lavorando, devo emulare uno scenario sincrono bloccando l'attesa di un messaggio (che è ovviamente asincrono). Nel frattempo, devo essere reattivo ai messaggi inviati dalla shell. Per qualche ragione in alcune circostanze la nostra shell personalizzata si blocca fino a quando non ho ricevuto quel messaggio, e non riesco a capire perché ... Tuttavia, la tua risposta su SendMessage è soddisfacente per il dubbio che ho avuto. – Wizard79

1

Ogni finestra è associata a una discussione. È possibile utilizzare GetWindowThreadProcessId per recuperare il thread di ogni finestra. Se si invia un messaggio a una finestra dall'altro thread in relazione a PostThreadMessage, il messaggio verrà inserito nella coda messaggi del thread. Il thread deve avere un ciclo get-message (con GetMessage per esempio) per ottenere i messaggi e inviarlo alla procedura della finestra della finestra.

Si chiama SendMessage anziché PostThreadMessage si chiama la procedura di Windows direttamente senza collocarla nella coda dei messaggi. Alcuni messaggi non elaborati vengono inviati anche immediatamente alla procedura della finestra di destinazione, ignorando la coda dei messaggi di sistema e la coda dei messaggi di thread. (vedi http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages).Il motivo principale per utilizzare SendMessage invece di PostThreadMessage se si desidera fornire alcune informazioni da un'altra finestra (controllo) come leggere un testo da un altro controllo durante l'elaborazione di un altro messaggio. Dovresti farlo solo se davvero necessario. Pertanto, se si utilizza SendMessage per inviare un messaggio a una finestra da un altro thread, il thread corrente deve essere bloccato per qualche tempo.

Può essere una buona idea usare PostThreadMessage o SendMessageCallback invece di SendMessage se è possibile.

+0

Grazie per la risposta, ma in realtà la domanda riguardava il fatto che internamente venisse chiamato SendMessage su un thread diverso, più precisamente come viene chiamata la routine della finestra di destinazione. – Wizard79

Problemi correlati