Domanda

Nell'applicazione Delphi è presente un thread con un ciclo di messaggi in attesa. Ogni volta che riceve un messaggio, inizia a fare un po 'di lavoro. Ecco la procedura di esecuzione di quel thread:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

Facendo alcuni test usando la mia applicazione ho scoperto che la funzione GetMessage dipende dal thread principale. Con questo intendo che mentre il thread principale sta facendo un po 'di lavoro, la funzione GetMessage nel mio thread non ritorna anche se un messaggio è in attesa di essere ricevuto da esso (il messaggio viene inviato da un altro thread utilizzando la funzione PostThreadMessage: PostMessage ( MyThreadId, WM_MyMessage, 0, 0)).

Solo quando il thread principale termina il suo lavoro o viene chiamato il metodo Application.ProcessMessages, GetMessage ritorna e il mio thread inizia a fare il suo lavoro. Implementando questo tipo di comunicazione tra thread ero sicuro che i miei thread avrebbero funzionato in modo indipendente e non mi sarei mai aspettato che la ricezione dei messaggi inviati direttamente a un thread dipendesse dal thread principale.

Durante i test ho usato la funzione WaitForSingleObject nel thread principale, in attesa di un evento per alcuni secondi. Questo è quando ho notato che il mio thread non stava facendo alcun lavoro anche se i messaggi gli erano stati inviati da un altro thread. Quando finalmente la funzione WaitForSingleObject ha terminato l'attesa e il thread principale è diventato inattivo, la funzione GetMessage nel mio thread è tornata.

Qualcuno potrebbe spiegarmi perché funziona in questo modo? C'è una soluzione a questo? Vorrei che il mio thread ricevesse messaggi in modo indipendente. Tutti i miei thread sono creati dal thread principale. Potrebbe essere questo il motivo?

Grazie per l'aiuto in anticipo.

Mariusz.


Mghie, avevi di nuovo ragione (mi hai aiutato con le cose di messaggistica di recente, potresti ricordare). Come hai suggerito, GetMessage ritorna immediatamente, ma il thread si blocca, infatti, su una chiamata a un metodo della finestra principale:

procedure TMyThread.Execute;
begin
  while GetMessage(Msg, 0, 0, 0) and not Terminated do
  begin
    {thread message}
    if Msg.hwnd = 0 then
    begin
      ...
      if Assigned(FOnCommEventMethod) then
        FOnCommEventMethod(FCommEventsQueueItem);
      ...
    end
    else
      DispatchMessage(Msg);
  end;
end;

FOnCommEventMethod è un metodo di oggetto, dichiarato come 'procedura (EventMask: Cardinal) di oggetto;' (questo thread gestisce gli eventi della porta seriale). In questo caso a FOnCommEventMethod è stata assegnata una procedura appartenente alla classe di modulo principale. Quando il metodo viene chiamato dal mio thread, il thread si blocca in attesa che il thread principale termini il suo lavoro.

Come mai? Come puoi vedere, non uso il metodo Synchronize () per chiamare questa procedura. Pertanto non mi aspetto che il mio thread si sincronizzi con il thread principale. Succede implicitamente? A proposito, capisco che nessun componente della GUI dovrebbe essere accessibile da nessun altro thread ma da quello principale, quindi dovrebbe essere usato il metodo Synchronize, ma sto facendo solo alcuni test rapidi ora.

Tornando all'argomento WaitForSingleObject, so che non dovrei usarlo, ma è stato solo un test grazie al quale (per coincidenza) ho notato il problema.

Grazie per l'aiuto. Se non mi avessi aiutato, probabilmente mi sarei sbarazzato della messaggistica e avrei usato gli eventi, e alla fine avrei notato che non era il motivo :-).

È stato utile?

Soluzione

  

Solo quando il thread principale termina il suo lavoro o viene chiamato il metodo Application.ProcessMessages, GetMessage ritorna e il mio thread inizia a fare il suo lavoro.

Dubito che questo sia davvero ciò che sta accadendo. AFAIK i due loop di messaggi dovrebbero essere indipendenti l'uno dall'altro, purché non si utilizzino altri mezzi per sincronizzare i thread, come SendMessage () . Sei sicuro che il thread si blocchi effettivamente all'interno di GetMessage () e non all'interno di Synchronize () (che utilizza SendMessage () internamente )?

  

Durante i test ho usato la funzione WaitForSingleObject nel thread principale, in attesa di un evento per alcuni secondi.

Non dovresti mai usare WaitForSingleObject () nel thread principale con un timeout più lungo di 100 millisecondi, in quanto ciò renderà la tua interfaccia grafica lenta. In effetti ti consiglierei di non usarlo affatto nel thread principale, perché questo è semplicemente polling. Pubblica invece un messaggio dal tuo thread di lavoro.

Altri suggerimenti

Puoi creare una coda di messaggi per il tuo thread. Basta eseguire il seguente codice nel thread:

MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
SetEvent(messageQueueReady);
while (GetMessage(&msg, NULL, 0, 0)) 
{
    ...// do message processing here
}

La chiamata a PeekMessage impone al sistema operativo di creare una nuova coda di messaggi per il thread. Devi assicurarti di sincronizzare questo, cioè devi aspettare (ad es. Tramite WaitForSingleObject) affinché la chiamata abbia successo prima di pubblicare messaggi su questo thread (ad es. Tramite PostThreadMessage). Ecco perché c'è una chiamata all'API SetEvent nell'esempio sopra.

Modifica: Ci scusiamo per l'esempio in C, spero che vada bene per te.

Vedi http: // groups.google.com/group/borland.public.delphi.language.delphi.win32/browse_thread/thread/cf368834a606321b

Distillazione richiesta, tralasciando molti dettagli nodosi in cui si nasconde il diavolo: il thread principale (o VCL) è speciale in Delphi perché molte cose sotto il cofano non sono thread-safe, e le possiede tutte. Cose come il loop di messaggi finiscono in attesa a causa di cose che si sincronizzano con il thread VCL sotto il cofano. Molte persone hanno teorie al riguardo. La cosa che sembra funzionare meglio è mantenere il tuo thread VCL il più leggero / reattivo possibile per ridurre al minimo le attese. Quasi tutti sono d'accordo su questo. Alcune persone hanno idee su altre cose che potrebbero funzionare, ma altre pensano che stiano solo chiedendo problemi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top