Threads: Send data to a specific active thread

168 views Asked by At

I have a rather curious problem. I have a multithreaded client server app built using Lazarus 1.4 and Indy 10 that I'm working on. It uses threads to send & receive data streams from the server. Each module creates its own self-terminating worker thread for this purpose. However I also need to create a special message worker thread that receives messages from the server like when a database backup is in progress. This message thread is created by the application mainform & remains active as long as the client application is active.

The server handles the sending of the data - message or database data - without problems. The issue is how to ensure that on the client side, server messages are read only by the message thread. All threads have Execute() procedures to process server communications.

My questions

  1. Will using a Thread ID for the message thread allow me to directly target the message thread when the server is passing a message.

  2. Alternatively, will limiting the messages to a certain size help in filtering messages meant for the client message thread (this is what I use actually but sometimes it fails).

Might I add that that all the client side threads use a common IdTCPClient to read server communications. I use critical sections to protect it.

The code for the message thread is shown below:

procedure TMsgThread.Execute;
var
  LBuffer: TBytes;
  LMessage: TBytes;
  LDataSize: Integer;
  LMsgProtocol: TMsgProtocol;
begin
  //inherited;   // Gives abstract methods cannot be called directly
  // while the thread is not terminated and the client is connected
  while NOT Terminated and FTCPClient.Connected do
  begin
    Lock;
    //
    try
      if not FTCPClient.IOHandler.InputBufferIsEmpty and
        (FTCPClient.IOHandler.InputBuffer.Size >= szMsgProtocol) and
        (FTCPClient.IOHandler.InputBuffer.Size < szProtocol) then
      begin
        InitMsgProtocol(LMsgProtocol);
        // store the size of the InputBuffer in LDataSize
        LDataSize := FTCPClient.IOHandler.InputBuffer.Size;
        if LDataSize >= szMsgProtocol then
          try
         // then read from InputBuffer the size of the protocol structure
            FTCPClient.IOHandler.ReadBytes(LBuffer, szMsgProtocol);
            // convert array of bytes to protocol
            LMsgProtocol := BytesToMsgProtocol(LBuffer);
            // check the command
            case LMsgProtocol.Command of
              cmdBackupDatabase:
                begin
                  //
                end; // cmdBackup: begin
              cmdPulse:
                begin
                  // Read the message sent by the server
                  FMessage := LMsgProtocol.Message;
                  // set the command to cmdKeepAlive
                  LMsgProtocol.Command := cmdKeepAlive;
                  // Convertir le protocol en bytes
                  LBuffer := MsgProtocolToBytes(LMsgProtocol);
                  // Envoyez la requĂȘte en bytes au serveur
                  FTCPClient.IOHandler.Write(LBuffer);
                  //
                  Synchronize(@Self.DoConnectionAlive);
                end;
            end; // case LProtocol.Command of
          finally
            // clear buffer and message
            ClearBuffer(LBuffer);
            ClearBuffer(LMessage);
          end; // tryf
        Sleep(100);
      end;
    finally
      Unlock;
    end;
  end; // while NOT Terminated and FTCPClient.Connected do begin
end;

The Execute methods for the other self-terminating threads are similar in structure to that shown above. I got it from a model on the Internet. szMsgProtocol is the size of the message protocol while szProtocol is the size of the data protocol. So essentially, in the Execute() above I am concerned with InputBuffer contents that have a size equal to or larger than the message protocol but strictly less than the data protocol. This is how I planned to sift the streams sent by the server.

0

There are 0 answers