if FChannel.Active then
begin
CodeSite.Send('Before deactivating channel');
FChannel.Active := False;
CodeSite.Send('After deactivating channel');
end;
FChannel is a TROSuperTCPChannel.
If the channel is successfully connected to a server, the FChannel.Active := False; line will run quickly. But if the channel is not connected to a server (ie. it is active, but has no connection), setting the FChannel.Active := False; will take around 4 seconds to run. Why is this, and can it be avoided?
You can ignore the CodeSite lines, they are just for roughly timing the call.
I realise now that I left out too much of my code in my initial posting to let you understand what I am trying to do.
I have a background TThread object that will try to connect to a host:port using TROSuperTCPChannel. Based on the result of this connect try, a few events will be called back to the UI thread. While the connection try is being made, the UI is showing some progress for ConnectionTimeout time (ms).
The question I had was if Channel.Active = True but there is no server responding so Channel.Connected = False, if I then try to set Channel.Active = False (or simply do Channel.Free), it will take around 3-4 seconds to do. This has the consequence that my thread will use 3-4 seconds to complete it’s Execute method and then be freed.
This is the entire Execute method of my thread:
procedure TServerConnectionTestThread.Execute;
var
TestState: TServerConnectionTestThreadState;
begin
TestState := csFailed;
FChannel.Host := Host;
FChannel.Port := Port;
FChannel.ConnectionWaitTimeout := ConnectionTimeout;
FChannel.ConnectTimeout := ConnectionTimeout;
FConnectionTryStartTime := GetTickCount;
InConnectionAttempt := True;
try
try
// Try to set active and wait for ConnectionTimeout
FChannel.WaitForActive(ConnectionTimeout);
// Check if connected to serer
if FChannel.Connected then
begin
TestState := csSuccessful;
end;
except
on E: EROSuperChannelException do
begin
// This Exception will occur if no connection was made
end;
end;
// Setting the State field will trigger either OnConnectionSuccessful or OnConnectionFailed events (Synchronized)
State := TestState;
FConnectionTryStartTime := 0;
finally
// Setting InConnectionAttemt to false before deactivating the channel. We do this because deactivating
// the channel can take some time and we want the user to be able to correct and try again before the
// channel is deactivated. The new try will be in a new thread anyway, and this thread will be freed when
// it completes automatically.
FInConnectionAttempt := False;
if FChannel.Active then
begin
FChannel.Active := False;
end;
end;
end;
pls undefine uROBaseSuperChannel_DEBUG in uROBaseSuperChannel.pas units and retest your code.
it can give some hints about issue
.
I think, it can be in TROBaseSuperChannel.SetInactive where is background thread that is used for connection to server, is freed.
The ConnectionTimeout is set to 3000 (3 seconds) so that might suggest that the Channel.Active = False actually waits for ConnectionTimeout before setting the Channel.Active to false even though it is not Channel.Connected=True.
I modified my code to include some timings and reported them by using CodeSite:
try
try
TimeBefore := GetTickCount;
FChannel.WaitForActive(ConnectionTimeout);
CodeSite.Send('Time to call WaitForActivate: %d ms', [GetTickCount - TimeBefore]);
if FChannel.Connected then
begin
TestState := csSuccessful;
end;
except
on E: EROSuperChannelException do
begin
CodeSite.Send('Time to call WaitForActivate: %d ms', [GetTickCount - TimeBefore]);
TimeBefore := GetTickCount;
end;
end;
State := TestState;
FConnectionTryStartTime := 0;
FConnectionTryEndTime := GetTickCount;
finally
// Setting InConnectionAttemt to false before deactivating the channel. We do this because deactivating
// the channel can take some time and we want the user to be able to correct and try again before the
// channel is deactivated. The new try will be in a new thread anyway, and this thread will be freed when
// it completes automatically.
FInConnectionAttempt := False;
CodeSite.Send('Time spent after WaitForActivate: %d ms', [GetTickCount - TimeBefore]);
if FChannel.Active then
begin
TimeBefore := GetTickCount;
FChannel.Active := False;
CodeSite.Send('Time to deactivate channel: %d ms', [GetTickCount - TimeBefore]);
end;
end;
The results are as follows:
Time to call WaitForActivate: 3047 ms
Time after WaitForActivate: 0 ms
Time to deactivate channel: 1516 ms
The strange thing is that on my home machine the time spent deactivating the channel when there is no server is only 1516 ms and not around 3-4 seconds as on my office PC.
I also tried to add a Sleep(2000) statement before deactivating the channel, and then the Time to deactivate channel was 0 ms!
It seems that the Channel is doing something after the WaitForActive call that on this machine takes around 1500 ms.
I did try to enable the debug output for uROBaseSuperChannel but it did not give me any useful information. Is there anything in particular here that you would want me to include?
if you add sleep(500) or sleep(1), will it improve situation or not? afaik, sleep suspends current thread and allows to other threads to do their work.
Using Sleep(500) or Sleep(1) did not improve the situation.
Summing up the value in Sleep() and adding the time it takes to call Channel.Active = False adds up to around 1500ms in total.
My conclusion is that if there is no server responding to the Channel.WaitForActive(3000) call, it will do something for at least 1500ms more afterwards before the Channel.Active=True completes or the Channel.Free completes.
I can’t reproduce this problem locally even with your piece of code.
Can you create a simple testcase that reproduces this, pls?
You can attach it here or send directly to support@