We have an application in which the user can talk to us, it works fine, he create a new conversation, we chat, and that's ok. But, before start chatting, he needs to connect to the DataSnap Server, and that's where I'm trying to make a Thread. Every 5min, a timer would trigger his event to create the Thread and try to connect on the server, as below:
My Thread:
unit UThreadSnapConnection;
interface
uses
System.Classes, System.SysUtils, Data.SqlExpr;
type
TThreadSnapConnection = class(TThread)
private
FSnap: TSQLConnection;
procedure TryToConnect;
protected
procedure Execute; override;
constructor Create;
public
DMSnap: TSQLConnection;
HostName: String;
Port: String;
end;
implementation
{ TThreadSnapConnection }
constructor TThreadSnapConnection.Create;
begin
inherited Create(True);
FreeOnTerminate := True;
end;
procedure TThreadSnapConnection.TryToConnect;
begin
try
FSnap := DMSnap.CloneConnection;
FSnap.Connected := False;
try
FSnap.Connected := True;
except
end;
if FSnap.Connected then
DMSnap.Connected := True;
finally
FreeAndNil(FSnap);
end;
end;
procedure TThreadSnapConnection.Execute;
begin
Synchronize(TryToConnect);
end;
end.
My Timer:
procedure TMyDataModuleSnap.TimerSnapTimer(Sender: TObject);
var
MyThread: TThreadSnapConnection;
begin
if not(MySQLConnection.Connected) then
begin
MyThread := TThreadSnapConnection.Create;
MyThread.DMSnap := MySQLConnection;
MyThread.HostName := 'localhost';
MyThread.Port := '211';
MyThread.Resume;
end;
end;
What I'm doing is an attempt to connect to the server, if it works, then it will make my data module connect.
My problem is, everytime the line
FSnap.Connected := True;
execute it freezes for 1~2 seconds the application, and the reason I made a thread was to not freeze. As long as I know, it should not bother at all the application, so I started to think maybe it's the work it does when setting the Connected property to True, which will freeze independent if it's thread or not.
Is there any way to not freeze when trying to connect?
And this is my first thread and maybe I just misunderstood things and that's not how thread works, but well, if it is not then I need to know, or at least understand what I'm doing wrong with it.
EDIT: The test I'm doing is, I start the application without starting the server, so it will try to connect unsuccessful, and my data module will not connect too.
There are two options:
OnTimer
event of a TTimer
is executed in the thread which has created the timer, you may consider to create the instance outside the main threadTThread
class instanceThe following applies to the #2.
Using a TEvent
in the Execute
procedure of your thread you can wait for an amount of FInterval
time before the execution of the next block of code.
When the Terminated
property is set to True
, this approach allows the Execute
method to immediately return also during the interval count unlike the adoption of a TThread.Sleep(FInterval);
call which would freeze the thread itself for the amount of time specified.
The main thread can be optionally notified using a TNotifyEvent
when done.
TMyThread = class(TThread)
private
FInterval: Integer;
FTerminateEvent: TEvent;
protected
procedure Execute; override;
procedure TerminatedSet; override;
public
OnEndJob: TNotifyEvent;
constructor Create(Interval: Cardinal; CreateSuspended: Boolean);
destructor Destroy; override;
end;
constructor TMyThread.Create(Interval: Cardinal; CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FInterval := Interval;
FTerminateEvent := TEvent.Create(nil, False, False, '');
end;
destructor TMyThread.Destroy;
begin
FTerminateEvent.Free;
inherited;
end;
procedure TMyThread.TerminatedSet;
begin
inherited;
FTerminateEvent.SetEvent;
end
procedure TMyThread.Execute;
begin
while not Terminated do begin
//do your stuff
//notify your connection to the main thread if you want
if Assigned(OnEndJob) then
Synchronize(procedure
begin
OnEndJob(Self);
end);
//wait fo some amount of time before continue the execution
if wrSignaled = FterminateEvent.WaitFor(FInterval) then
Break;
end;
end;
Don't synchonize the code you want to be executed in a thread: in Delphi a syncronized block is always executed in the calling thread.