Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

Peekmessage problem

[es] :: Pascal / Delphi / Kylix :: Peekmessage problem

[ Pregleda: 2876 | Odgovora: 9 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

Boris B.
Ljubljana

Član broj: 213615
Poruke: 286
*.dial-up.dsl.siol.net.



+14 Profil

icon Peekmessage problem07.03.2009. u 10:16 - pre 184 meseci
Imam jedan prilicno specifican problem, naime, poziv Windows API funkcije PeekMessage izazove da se sve pending poruke poslane sa SendMessage proslede WndProc funkciji.

Imam threadove koji imaju svaki svoj window handle i message loop, tj. komuniciraju medjusobno iskljucivo preko Send/Post message API funkcija. Sve radi fenomenalno, ali problem nastaje kada jedan thread ceka na window poruku drugog threada:

Code:

//thread koji ceka
var
  Msg: tagMsg;
  ...
  while (not PeekMessage(Msg, FHandle, WaitedMsg, WaitedMsg, PM_REMOVE or PM_NOYIELD)) and (not FThread.Terminated) do
    Sleep(1);
  //ovde imam poruku koju cekam
  ...


Samo cekanje radi, problem je sto dok thread ceka na poruku WaitedMsg, ako drugi thread posalje nesto sa SendMessage to ce se obraditi odmah (direktno se poziva WndProc), jer izgleda da jedan poziv PeekMessage izazove da se obrade sve poruke poslane sa SendMessage. Kako to da izbegnem? Ima li mozda neki drugi nacin da dodjem do svojih poruka a da ne koristim Peek ili Get Message?


if it walks like a duck and quacks like a duck, it could be a dragon doing a duck
impersonation.
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: Peekmessage problem07.03.2009. u 18:03 - pre 184 meseci
> Imam threadove koji imaju svaki svoj window handle i message loop, tj. komuniciraju medjusobno iskljucivo preko Send/Post message API funkcija.

Pravio si poseban window handle za svaki thread, da li si koristio CreateWindow? Možeš li da koristiš thread queue umesto (ne treba poseban window, ali se poruke mogu samo postovati).

while (not PeekMessage(Msg, FHandle, WaitedMsg, WaitedMsg, PM_REMOVE or PM_NOYIELD)) and (not FThread.Terminated) do
Sleep(1);
//ovde imam poruku koju cekam
...

> Samo cekanje radi, problem je sto dok thread ceka na poruku WaitedMsg, ako drugi thread posalje nesto sa SendMessage to ce
> se obraditi odmah (direktno se poziva WndProc), jer izgleda da jedan poziv PeekMessage izazove da se obrade sve poruke poslane
> sa SendMessage. Kako to da izbegnem? Ima li mozda neki drugi nacin da dodjem do svojih poruka a da ne koristim Peek ili Get Message?

Dok traje izvršavanje PeekMessage procesiraju se poruke poslate sa SentMessage. Možeš pokušati da staviš PM_QS_POSTMESSAGE or PM_REMOVE kao flag, ako to ne pomogne moraćeš da revidiraš sistem slanja.
 
Odgovor na temu

Boris B.
Ljubljana

Član broj: 213615
Poruke: 286
*.dial-up.dsl.siol.net.



+14 Profil

icon Re: Peekmessage problem08.03.2009. u 11:20 - pre 184 meseci
>Pravio si poseban window handle za svaki thread, da li si koristio CreateWindow?
Ne direktno, koristio sam Delphi-jev budz Classes.AllocateHWnd, koji kreira dummy window tipa UtilWindow pomocu CreateWindowEx. Rezultat je da dobijes pravi window handle i registurej svoj WndProc iz TObject naslednika, znaci ne moras da nasledjujes neefikasan TWinControl samo da bi imao window handle (Tako radi npr. TTimer koji je TComponent a ima window handle za WM_Timer poruku).

>Možeš li da koristiš thread queue umesto (ne treba poseban window, ali se poruke mogu samo postovati)
Ne mogu bas iz tog razloga, sto onda ne radi SendMessage. Kada mi svi threadovi imaju window handle onda mogu da radim i Send i PostMessage, Post kada hocu asinhrono (non-blocking) da pozivam metode drugih threadova i Send kada hocu sinhrono (blocking) da bih odmah dobio rezultat kada je to potrebno. Uposte ne moram da razimsljam o implementaciji metoda koji pozivam. Ceo sistem radi perfektno, jedino se kasnije pokazalo da mi je potrebno jos i cekanje na odredjenu poruku koja ce uvek stici sa PostMessage, znaci u message queue. Problem je u tome da dok se ceka na poruku preko onog koda thread nije blokira, ako neki thread posalje nesto sa SendMsg to se obradi odmah sto potencijalno dovede do jos jednog cekanja. Kada prvi odgovor konacno stigne, stigne u onu granu koja je poslednja cekala a ne prva.

>Možeš pokušati da staviš PM_QS_POSTMESSAGE or PM_REMOVE kao flag, ako to ne pomogne moraćeš da revidiraš sistem slanja.
PM_QS_POSTMESSAGE ne pomaze, probao sam. Isto tako ni critical sectioni ne pomazu (logicno, ne mozes da zakljucas samog sebe), a neki Boolean flegovi tipa FWaiting naravno izazovu deadlock threada koji ceka. Izgleda da cu stavrno moarati da revidiram sistem slanja, probacu sa TEventom.




if it walks like a duck and quacks like a duck, it could be a dragon doing a duck
impersonation.
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: Peekmessage problem08.03.2009. u 16:10 - pre 184 meseci
> Ne direktno, koristio sam Delphi-jev budz Classes.AllocateHWnd, koji kreira dummy window tipa UtilWindow pomocu CreateWindowEx.

Pretpostavio sam da je tako, samo da te upozorim daAllocateHWnd nije threadsafe, u nekim retkim situacijama može doći do problema. Evo teksta koji to opširno objašnjava http://17slon.com/blogs/gabr/2...tehwnd-is-not-thread-safe.html

> tipa FWaiting naravno izazovu deadlock threada koji ceka. Izgleda da cu stavrno moarati da revidiram sistem slanja, probacu sa TEventom.

Ja sam nešto slično pravio, evo otprilike ideje:

Code:


unit ThreadUnit;

interface

uses
  Windows, Classes, Messages;

const
  MSG_SEND = WM_APP + 1;
  MSG_CALC = WM_APP + 2;

type
  TMyThread = class(TThread)
  private
    procedure ProcessMessages;

    procedure MsgSend(var Msg: TMessage); message MSG_SEND;
    procedure MsgCalc(var Msg: TMessage); message MSG_CALC;
  protected
    procedure Execute; override;
  public
    function SendMsg(Msg: UINT; wParam: Longint; lParam: Longint): Longint;
  end;


implementation

type
  TSendHelper = packed record
    Msg: UINT;
    lParam: Longint;
    wParam: Longint;
    Result: Longint;
    Event: THandle;
  end;

{ TMyThread }

procedure TMyThread.Execute;
var
  msg: TMsg;
begin
  PeekMessage(msg, 0, WM_NULL, WM_NULL, PM_NOREMOVE);

  while not Terminated do
  begin
    Sleep(100);
    ProcessMessages;
  end;
end;

procedure TMyThread.MsgCalc(var Msg: TMessage);
begin
  Msg.Result := Msg.LParam * Msg.WParam;
end;

procedure TMyThread.MsgSend(var Msg: TMessage);
var
  Temp: TSendHelper;
  TempMsg: TMessage;
begin
  Temp := TSendHelper(Pointer(Msg.wParam)^);
  TempMsg.Msg := Temp.Msg;
  TempMsg.wParam := Temp.wParam;
  TempMsg.lParam := Temp.lParam;
  try
    Dispatch(TempMsg);
    Temp.Result := TempMsg.Result;
    SetEvent(Temp.Event);
  except

  end;
end;

procedure TMyThread.ProcessMessages;
var
  msg: TMsg;
  Temp: TMessage;
begin
  // Preuzimamo i procesiramo sve poruke koje se trenutno nalaze u message queueu ovog treada
  while PeekMessage(msg, INVALID_HANDLE_VALUE, 0, 0, PM_REMOVE) do
  begin
    Temp.Msg := msg.message;
    Temp.wParam := msg.wParam;
    Temp.lParam := msg.lParam;
    try
      Dispatch(Temp);
    except

    end;
  end;
end;

function TMyThread.SendMsg(Msg: UINT; wParam: Longint; lParam: Longint): Longint;
var
  Temp: TSendHelper;
begin
  Temp.Event := CreateEvent(nil, True, False, nil);
  Temp.Msg := Msg;
  Temp.lParam := lParam;
  Temp.wParam := wParam;
  PostThreadMessage(ThreadID, MSG_SEND, Longint(@Temp), 0);
  WaitForSingleObject(Temp.Event, INFINITE);
  Result := Temp.Result;
  CloseHandle(Temp.Event);
end;

end.

I pozivanje: 
  FThread := TMyThread.Create(False);
  Caption := IntToStr(FThread.SendMsg(MSG_CALC, 343, 222));

 
Odgovor na temu

Boris B.
Ljubljana

Član broj: 213615
Poruke: 286
*.dial-up.dsl.siol.net.



+14 Profil

icon Re: Peekmessage problem08.03.2009. u 23:46 - pre 184 meseci
>samo da te upozorim da AllocateHWnd nije threadsafe
Znam, zato sam zamotao AllocateHWnd u utitlity funkciju sa critical section-om, i posto je koristi samo TTimer i moje klase onda nije problem

>Ja sam nešto slično pravio, evo otprilike ideje
U prinicipu to je to, TEvent resava posao, na svu srecu u mom serveru se samo na par mesta koristi cekanje na poruku tako da nece biti neki problem to implementirati.

Hvala za odgovor i savete.
if it walks like a duck and quacks like a duck, it could be a dragon doing a duck
impersonation.
 
Odgovor na temu

priki

Član broj: 24732
Poruke: 700
*.datalab.si.

ICQ: 174153511


+26 Profil

icon Re: Peekmessage problem09.03.2009. u 08:57 - pre 184 meseci
zašto ne koristiš GetMessage() i MsgWaitForMultipleObjects()
oni blokiraju thread ako nema poruka
tako thread ne "prži" procesor bez veze

[Ovu poruku je menjao priki dana 09.03.2009. u 10:42 GMT+1]
 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 810
79.101.217.*



+62 Profil

icon Re: Peekmessage problem09.03.2009. u 11:55 - pre 184 meseci
Moram da se zahvalim savkic-u na gore postovanom kodu; prava mala skolica.

Bio sam nacuo da thread-ovi mogu da komuniciraju medju sobom, ali nisam nikad pokusao (nije mi trebalo). Sve u svemu, ova tema mi je ulepsala jutro (hvala i Borisu) - uvek sam srecan kad nesto naucim :) .
Hvala jos jednom i pozdrav

Rajko
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: Peekmessage problem09.03.2009. u 13:04 - pre 184 meseci
> zašto ne koristiš GetMessage() i MsgWaitForMultipleObjects()
> oni blokiraju thread ako nema poruka

Nema razlike između GetMessage i PeekMessage, dok čekaju obrađuju non-qued poruke (poruke poslate sa SendMessage, SendMessageTimeout...)
 
Odgovor na temu

Boris B.
Ljubljana

Član broj: 213615
Poruke: 286
*.dial-up.dsl.siol.net.



+14 Profil

icon Re: Peekmessage problem10.03.2009. u 00:01 - pre 184 meseci
>zašto ne koristiš GetMessage() i MsgWaitForMultipleObjects() oni blokiraju thread ako nema poruka tako thread ne "prži" procesor bez veze
I koristim GetMessage u glavnom message loop-u, samo sam probao sistem za cekanje tj. taj mini-message-loop sa PeekMsg misleci da PeekMessage ne izaziva obradu poruka poslanih sa SendMessage, ali se ispostavilo da i Get i Peek izazivaju obradu poruka poslanih sa Send, sto je nezeljeni efekat u mom slucaju.

Druga stvar, "while True do Sleep(1)" ne przi procesor ama bas nista, jer se pri svakoj iteraciji thread suspenduje na jednu minimalnu rezoluciju tajmera (obicno oko 16ms). Sleep(0) sa druge strane pojede ceo procesor jer uopste ne prepusta procesorsko vreme ako nema drugog threada koji ceka na izvrsenje sa istim ili visim prioritetom. Znaci uvek Sleep(1) nikad Sleep(0) kao rule of thumb

>Nema razlike između GetMessage i PeekMessage, dok čekaju obrađuju non-qued poruke
Pa nije bas tako, PeekMessage ne ceka nista ali ipak izazove obradu non-queued poruka...
if it walks like a duck and quacks like a duck, it could be a dragon doing a duck
impersonation.
 
Odgovor na temu

savkic
Igor Savkić

Moderator
Član broj: 92186
Poruke: 2739



+92 Profil

icon Re: Peekmessage problem10.03.2009. u 02:11 - pre 184 meseci
>> Nema razlike između GetMessage i PeekMessage, dok čekaju obrađuju non-qued poruke
> Pa nije bas tako, PeekMessage ne ceka nista ali ipak izazove obradu non-queued poruka...

Pa dobro, dok čekaju da se završe ili dok se izvršavaju... ;)
 
Odgovor na temu

[es] :: Pascal / Delphi / Kylix :: Peekmessage problem

[ Pregleda: 2876 | Odgovora: 9 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.