Until now, I was calling the following function every second :
function TForm1.ListeConnecteMaj():Boolean;
var
i : integer;
List : TIdContextList;
Client : TSimpleClient;
begin
List := TCPServer1.Contexts.LockList;
try
NbSConnect := List.Count;
for i := 0 to List.Count -1 do
begin
Client := List[i];
..... // getting information from Client
end;
finally
TCPServeur1.Contexts.UnlockList;
end;
end;
As I need to support hundreds of simultaneaous connections, I want to reduce as much as possible the duration of the LockList. I've tried this. It works but is it really safe ?
function TForm1.ListeConnecteMaj():Boolean;
var
i : integer;
List : TIdContextList;
Client : TSimpleClient;
begin
List := TCPServer.Contexts.LockList;
TCPServeur.Contexts.UnlockList;
try
NbSConnect := List.Count;
for i := 0 to List.Count -1 do
begin
Client := List[i];
..... // getting information from Client
end;
finally
end;
end;
CodePudding user response:
It works but is it really safe?
No, it is not thread-safe.
You can safely use List
reference acquired by LockList
until you call UnlockList
. The moment you call UnlockList
, list will no longer be protected and any List
access after that point can cause concurrency issues.
Your original code is the proper way to use LockList/UnlockList
.
CodePudding user response:
As @DalijaPrasnikar's answer explains, your proposal is not safe, no. As soon as the list is unlocked, the server is able to freely modify the contents of the list as clients connect and disconnect, which will cause concurrency issues with your code.
I would suggest a different approach - rather than polling the client list every second, I would use the OnConnect
and OnDisconnect
events to add/remove elements from your UI as needed whenever the client list changes. If you are trying to track status updates per client during socket operations, you can post notifications to the main UI thread as they happen.