Search code examples
delphiclient-serverindy

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


Solution

  • 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;