Question

In this code, as you see on Connect, AContext.Data is filled with something

TmyTThreadList = class(TThreadList)
  id: integer;
end;

var unique_id:integer;

procedure TfrmTestIdTCPServer.IdTCPServerConnect(AContext: TIdContext);
 begin
  CS.Enter;
  try
    inc(unique_id);
  finally
    CS.Leave;
  end;

   AContext.Data := myTThreadList.Create;
   list := myTThreadList(AContext.Data).LockList;
   try
     myTThreadList(AContext.Data).id := my_unique_id;
     list.Add(myTThreadList(AContext.Data));
   finally
     myTThreadList(AContext.Data).UnlockList;
   end;
 end;

then on disconnect, coder is checking here for Acontext.Data <> nil

procedure TfrmTestIdTCPServer.IdTCPServerDisconnect(AContext: TIdContext);
 var
 begin
   if AContext.Data <> nil then
   begin

The question is, why he is checking for nil ?

Thanks.

EDIT:

I'm asking this, because when I do the same, onExecute I access AContext.Data , and sometimes (when in same time is connecting many clients) AContext.Data is empty, access violation appears.

Was it helpful?

Solution

The original programmer can check if Data is nil for a number of different reasons, the only way to really know that is to ask him/her why did it that way.

What I think could be is:

  • Even when to any connection a new Data object is created, this object could be freed during the lifetime of the connection, for any other number or reasons. For example, in the OnExecute event handler for that server component as a consequence of the data stored there or by request coming from the client or other external source.
  • Maybe the code to be executed during the lifetime of the connection is out of the original programmer control, so he/she have no other way to know if the Data object is still there, e.g. a component writer should do that kind of test, or a library programmer working in a team.
  • The original coder is just the kind of defensive programmer and is applying the check even when he/she knows the Data object is supposed to be there, but just to be sure it is and prevent an accidental Access Violation.

As for you concern, AFAIK, Indy does not touch the Data object but in the Destroy sequence for the Task instance.

The TIdTask.Data documentation states:

A user-specified object with values used during execution of the task. Data is a TObject property that represents a user-specified object instance with values that can be used during execution of the task.

An object instance must be assigned to Data after creation of the task in Create.

The Data property is owned by the TIdTask instance, and will be freed in Destroy.

And does not mention any case in which Data is Freed by Indy itself.

I did a test assigning a object to a new connection, doing some work with it in a server and doing multiple connections from a client, and after various thousands of connections no one have failed to keep the correct Data object attached to the AContext in each call, not only to OnDisconnect but also to the OnExecute event.

OTHER TIPS

If an uncaught exception occurs in the OnConnect event handler, the OnDisconnect event can still be called. If the exception is raised by TThreadList.Create then AContext.Data will not be assigned.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top