Adrian
Adrian

Reputation: 323

Delphi (Indy) Server Freezing on Write

I currently have stable code between a client (IdTCPClient) and a server (IdTCPServer) working all as planned. When I call the following function from an OnClick event of a button, however, the server freezes.

var
  SendStream: TMemoryStream;
  FileStream: TFileStream;
  List: TList;
  I: Integer;
begin
  try
    //Load
    FileStream := TFileStream.Create(Path, fmOpenRead);
    FileStream.Position := 0;
    //Place into stream
    SendStream := TMemoryStream.Create;
    SendStream.Write(Header, SizeOf(Header)); //This works; supporting code ommitted  for brevity
    SendStream.CopyFrom(FileStream, FileStream.Size);
    SendStream.Position := 0;

    TIdContext(fTCP.Contexts.LockList[0]).Connection.IOHandler.Write(SendStream, 0, True);
    fTCp.Contexts.LockList;
   if Assigned(Self.fServerOnSync) then Self.fServerOnSync(SizeOf(Header)) //event handler for main form

  finally
    FileStream.Free;
    SendStream.Free;
  end;

I am guessing it has something to do with deadlocking threads but for the life of me I have no idea why it's occuring.

Also, if I encapsulate the above code in some class that contains the IdTCP server, which will call my custom fServerOnSync event, is this threadsafe?

Cheers, Adrian

Upvotes: 1

Views: 1130

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596287

You are calling fTCp.Contexts.LockList() twice, but you are not calling fTCp.Contexts.UnlockList() at all, so the server will become deadlocked whenever it tries to access the Contexts list. You need to unlock the list after you have locked it, eg:

var 
  SendStream: TMemoryStream; 
  FileStream: TFileStream; 
  List: TList; 
  I: Integer; 
begin 
  FileStream := TFileStream.Create(Path, fmOpenRead or fmShareDenyWrite); 
  try 
    SendStream := TMemoryStream.Create; 
    try
      SendStream.Write(Header, SizeOf(Header));
      SendStream.CopyFrom(FileStream, FileStream.Size); 
      SendStream.Position := 0; 

      List := fTCP.Contexts.LockList; 
      try
        TIdContext(List[0]).Connection.IOHandler.Write(SendStream, 0, True); 
      finally
        fTCP.Contexts.UnlockList; 
      end;
      if Assigned(fServerOnSync) then fServerOnSync(SizeOf(Header)); 
    finally 
      SendStream.Free; 
    end; 
  finally
    FileStream.Free; 
  end;
  ...
end;

Upvotes: 1

Related Questions