Page 1 of 1

TOraAlerter won't shoot event in a thread under certain circumstances

Posted: Sun 05 Mar 2006 10:25
by MageRain
This is not exactly a bug, I found a workaround, but it still feels weird to code that way.

Suppose I have a thread, and I want it to wait for event do something then wait for event again.
So it's something like this:

procedure TMyThread.OraAlerter1Event(Sender: TObject; Event, Message: String);
begin
SetEvent(alev);
somethinghappened:=True;
eventreceived:=True;
Continue:=False;
end;

procedure TMyThread.OraAlerter1TimeOut(Sender: TObject;var Continue: Boolean);
begin
SetEvent(alev);
eventreceived:=False;
somethinghappened:=True;
Continue:=False;
end;


TMyThread.Execute;
begin
While not(terminated) do
begin
OraAlerter.TimeOut:=1;{one is for debug purposes it maybe whatever}
OraAlerter.Interval:=0;
OraAlerter.Events:=ename;
eventrecieved:=False;
OraAlerter.Active:=True;

//not working code
WaitForSingleObject(alev,INFINITE);{event doesn't shoot this way}

//working code
While not(somethinghappened) do application.Processmessages; {event shoots this way}

OraAlerter.Active:=False;
If eventrecieved DoSomethingUseful;
end;
end;


Well in this case neither OraAlerter1Event nor OraAlerter1TimeOut won't shoot. But if you discard
events and make a cycle there with application.Processmessages then it is going to work. This is
not main thread, it's separate thread so it doesn't have to process no messages whatsoever.

Posted: Tue 07 Mar 2006 14:05
by Challenger
When you activate OraAlerter in you thread it creates a separate thread that executes sql statements. So when you call WaitForSingleObject you block your thread because the thread that was created by OraAlerter can't call OraAlerter1Event and OraAlerter1TimeOut events. That's why the workaround with Application.ProcessMessages works fine, unlike calling WaitForSingleObject function.

Posted: Thu 09 Mar 2006 12:26
by MageRain
I don't demand answers or anything, I just have some experience working with threads and know how hard it is to debug them thouroghfully sometimes and know that recorded unexpected thread behaviour is often the only clue to make thread work in all possible conditions as is expected.
So take this just as an insight I wish to share.

I understand that TOraAlerter creates separate thread. And when my thread calls waitforsingleobject it blocks my thread. But this doesn't or at least shouldn't block TOraAlerter thread.
And event calling will not be blocked. Thread event is basically function which can be called by anybody with enough scope. It will be run from any thread which calls it, whether the execute function runs or not. That is if you do something like:

///////////////////////////////////////////////////////////////////////
{Thread 1}
unit Unit2;

interface

uses
Classes,dialogs,unit3,windows;

type
Thread1 = class(TThread)
constructor create;
destructor destroy;override;
private
mev:integer;
childthread:Thread2;
procedure onChildEvent(Sender:TObject);
protected
procedure Execute; override;
end;

implementation

constructor Thread1.create;
begin
inherited Create(True);
childthread:=Thread2.Create(onChildEvent);
mev:=CreateEvent(nil,False,False,'testevent');
Resume;
end;

destructor Thread1.destroy;
begin
childthread.Free;
Terminate;
SetEvent(mev);
WaitFor;
inherited Destroy;
end;

procedure Thread1.onChildEvent(Sender:TObject);
begin
SetEvent(mev);
end;

procedure Thread1.Execute;
begin
While not(terminated) do
begin
WaitForSingleObject(mev,INFINITE);
ShowMessage('event set');
end;
end;

end.

///////////////////////////////////////////////////////////////////////
{Thread 2}


unit Unit3;

interface

uses
Classes,windows;

type
Thread2 = class(TThread)
constructor Create(a:Tnotifyevent);
private
{ Private declarations }
b:TNotifyEvent;
protected
procedure Execute; override;
end;

implementation

constructor Thread2.Create(a:Tnotifyevent);
begin
inherited Create(True);
b:=a;
Resume;
end;

procedure Thread2.Execute;
begin
{ Place thread code here }
While not(terminated) do
begin
Sleep(5000);
b(nil);
end;
end;

end.

///////////////////////////////////////////////////////////////////////

It will call event. I can't ever imagine what kind of processing should be executed in TOraAlerter thread to produce results when it won't call event when creating thread won't process messages.
Even if TOraAlerter thread would be dependent on messages there is main thread processing them for application whether child threads are suspended or not.

Posted: Fri 10 Mar 2006 09:54
by Challenger
When the thread that was created by TOraAlerter finishes it sends a message to TOraAlerter (to the window that was created by TOraAlerter). But TOraAlerter can't process this message because your thread is being blocked. When you call Application.ProcessMessages you process messages from the thread (your thread) message queue. That's why TOraAlerter can process message from its thread and can call one of its events.