Multithreading 如何在已经运行的线程中运行代码以安全地发送/recv数据[TidTCPServer]

Multithreading 如何在已经运行的线程中运行代码以安全地发送/recv数据[TidTCPServer],multithreading,delphi,thread-safety,indy,delphi-xe8,Multithreading,Delphi,Thread Safety,Indy,Delphi Xe8,更新问题仍然存在 可以在已经运行的线程中运行代码吗?例如: thread1正在运行一些代码&我想在thread1中运行thread2中的代码 我想在idTCPServer线程中运行代码,以便向客户端发送一些数据 编辑: 经过研究,我的问题似乎是,当客户端数据被接收或同时被另一个线程试图写入该套接字时 编辑: procedure TMainFrm.UserSRVExecute(AContext: TIdContext); var Command : String; msSize

更新问题仍然存在

可以在已经运行的线程中运行代码吗?例如: thread1正在运行一些代码&我想在thread1中运行thread2中的代码


我想在idTCPServer线程中运行代码,以便向客户端发送一些数据

编辑: 经过研究,我的问题似乎是,当客户端数据被接收或同时被另一个线程试图写入该套接字时

编辑:

procedure TMainFrm.UserSRVExecute(AContext: TIdContext);
var
 Command        : String;
 msSize         : Int64;
 ms             : TMemoryStream;
 decompressedMS : TMemoryStream;
 H              : TIdNotify;
begin
// Application.ProcessMessages;
 Command := AContext.Connection.Socket.ReadLn;
// messagebox(0,'snd','',$40);
 if logb then mainfrm.mconnections.Lines.Add(command + ' - BEGIN');

 if Command <> '' then   // keepalive 
  begin
  //Application.ProcessMessages;
   msSize         := AContext.Connection.Socket.ReadInt64;
   ms             := TMemoryStream.Create;
   decompressedMS := TMemoryStream.Create;
   try
    AContext.Connection.Socket.ReadStream(ms, msSize);
    ms.Position := 0;
    DecompressStream(MS,decompressedMS);
    decompressedMS.Position := 0;
    Client_ProcessData(AContext,Command,decompressedMS);
   finally
    ms.Free;
    decompressedMS.Free;
    if logb then mainfrm.mconnections.Lines.Add(command + ' - END');
   end;
  end;
end;


procedure Client_ProcessData(AContext: TIdContext; cmd : String; data : TMemoryStream);
var
 Hnd     : THandle;
 clData  : TStringArray;
 TmpStr1 : String;
 Tmp     : String;
 TN      : TIdNotify;

 Sync    : TMySync;
 I,I2    : Integer;
begin
 Hnd := AContext.Connection.Socket.Binding.Handle;

 if cmd = 'scr' then  // RECEIVE COMMAND TO SEND TO CLIENT TO RECEIVE DATA FROM CLIENT
  begin
   Tmp := StreamToString(data);
   {Sync := TMySync2.Create(True);
   try
    Sync.cmd := cmd;
    Sync.hnd := Hnd;
    Sync.tmp := TmpStr1;
    Sync.Resume;
   finally
    //Sync.Free;
   end;  }
   log('>>> CLFROMAS: '+IntToStr(HND)+':::'+cmd+':::');
 //  SendCMDToSocket(MainFrm.UserSRV,StrToInt(Trim(Tmp)),'scr'+IntToStr(Hnd));
   I2 := StrToInt(Trim(Tmp));
  for I := 0 to 100 do
  if USRVData[i].hnd = I2 then
   begin
   // cs.Acquire;
    USRVData[i].CTX.Connection.Socket.WriteLn('scr'+IntToStr(Hnd));  // PLACED ALL CONTEXTs IN GLOBAL VARIABLE + ALL SOCKET HANDLES. <--- HERE IS THE PROBLEM
   // cs.Release;
    Break;
   end;
 //  log('>>> CLFROMAS: '+IntToStr(HND)+':::'+cmd+':::'+streamtostring(data));
   Exit;
  end;

   if Copy(cmd,1,Length('scr4u')) = 'scr4u' then // RECEIVE DATA FROM CLIENT TO SEND IT TO ADMIN CLIENT REQUEST ABOVE
   begin
    if Length(cmd) > Length('scr4u') then
     begin
      Delete(cmd,1,Length('scr4u'));
      Data.Position := 0;
     { Sync := TMySync.Create;
      try
       Sync.cmd := cmd;
       Sync.hnd := Hnd;
       Sync.data := TMemoryStream.Create;
       Sync.data.CopyFrom(data,data.Size);
       Sync.data.Position := 0;
       Sync.DoNotify;
      finally
       Sync.data.Free;
       Sync.Free;
      end;  }
      SendStreamToSocket(MainFrm.UserSRV,strtoint(cmd),'scr4u',Data);

      log('>>>>> ADMIN: '+IntToStr(HND)+':::'+cmd+':::'{+streamtostring(data)});
     end else TmpStr1 := '';
    Exit;
   end;

   ...
过程tmainfm.UserSRVExecute(AContext:TIdContext);
变量
命令:字符串;
msSize:Int64;
ms:TMemoryStream;
解压缩DMS:TMemoryStream;
H:TID通知;
开始
//Application.ProcessMessages;
命令:=AContext.Connection.Socket.ReadLn;
//消息框(0,'snd','',40美元);
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-BEGIN');
如果命令为“”,则//keepalive
开始
//Application.ProcessMessages;
msSize:=AContext.Connection.Socket.ReadInt64;
ms:=TMemoryStream.Create;
解压缩DMS:=TMemoryStream.Create;
尝试
AContext.Connection.Socket.ReadStream(ms,msSize);
女士职位:=0;
解压流(MS,解压DMS);
解压DMS.位置:=0;
客户端处理数据(文本、命令、解压DMS);
最后
弗里女士;
解压dms.Free;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-END');
结束;
结束;
结束;
过程客户机_ProcessData(AContext:TIdContext;cmd:String;data:TMemoryStream);
变量
Hnd:THandle;
clData:TStringArray;
TmpStr1:字符串;
Tmp:字符串;
TN:TIdNotify;
同步:TMySync;
一、 I2:整数;
开始
Hnd:=AContext.Connection.Socket.Binding.Handle;
如果cmd='scr',则//RECEIVE命令发送到客户端以从客户端接收数据
开始
Tmp:=StreamToString(数据);
{Sync:=TMySync2.Create(True);
尝试
Sync.cmd:=cmd;
Sync.hnd:=hnd;
Sync.tmp:=TmpStr1;
同步。恢复;
最后
//同步。免费;
结束;}
log('>>>CLFROMAS:'+IntToStr(HND)+':'+cmd+':');
//SendCMDToSocket(MainFrm.UserSRV、stroint(Trim(Tmp))、'scr'+IntToStr(Hnd));
I2:=stroint(微调(Tmp));
对于I:=0到100 do
如果USRVData[i].hnd=I2,则
开始
//cs.收购;
USRVData[i].CTX.Connection.Socket.WriteLn('scr'+IntToStr(Hnd));//将所有上下文放置在全局变量+所有套接字句柄中。长度('scr4u'),然后
开始
删除(cmd,1,长度('scr4u'));
数据位置:=0;
{Sync:=TMySync.Create;
尝试
Sync.cmd:=cmd;
Sync.hnd:=hnd;
Sync.data:=TMemoryStream.Create;
Sync.data.CopyFrom(数据、数据、大小);
Sync.data.Position:=0;
Sync.DoNotify;
最后
Sync.data.Free;
同步。免费;
结束;}
SendStreamToSocket(MainFrm.UserSRV,stroint(cmd),'scr4u',数据);
日志('>>>>管理员:'+IntToStr(HND)+'::'+cmd+'::'{+streamtostring(data)});
end else TmpStr1:='';
出口
结束;
...
更新

procedure TMainFrm.UserSRVExecute(AContext: TIdContext);
var
 Command        : String;
 msSize         : Int64;
 ms             : TMemoryStream;
 decompressedMS : TMemoryStream;
 H              : TIdNotify;
 I              : Integer;
 List, Messages : TStringList;
begin
  Messages := nil;
  try
   List := TMyContext(AContext).OutgoingMessages.Lock;
   try
    if List.Count > 0 then
     begin
      Messages := TStringList.Create;
      Messages.Assign(List);
      List.Clear;
     end;
   finally
    TMyContext(AContext).OutgoingMessages.Unlock;
   end;
   if Messages <> nil then
    begin
     for I := 0 to Messages.Count-1 do
      begin
       AContext.Connection.IOHandler.WriteLn(Messages.Strings[I]);
      end;
    end;
  finally
   Messages.Free;
  end;

  if AContext.Connection.IOHandler.InputBufferIsEmpty then
   begin
    AContext.Connection.IOHandler.CheckForDataOnSource(100);
    AContext.Connection.IOHandler.CheckForDisconnect;
    if AContext.Connection.IOHandler.InputBufferIsEmpty then
      Exit;
   end;

 Command := AContext.Connection.Socket.ReadLn;

 if logb then mainfrm.mconnections.Lines.Add(command + ' - BEGIN');

 if Command <> '' then
  begin
   msSize         := AContext.Connection.Socket.ReadInt64;
   ms             := TMemoryStream.Create;
   decompressedMS := TMemoryStream.Create;
   try
    AContext.Connection.Socket.ReadStream(ms, msSize);
    ms.Position := 0;
    DecompressStream(MS,decompressedMS);
    decompressedMS.Position := 0;
    Client_ProcessData(AContext,Command,decompressedMS);
   finally
    ms.Free;
    decompressedMS.Free;
    if logb then mainfrm.mconnections.Lines.Add(command + ' - END');
   end;
  end;
end;
过程tmainfm.UserSRVExecute(AContext:TIdContext);
变量
命令:字符串;
msSize:Int64;
ms:TMemoryStream;
解压缩DMS:TMemoryStream;
H:TID通知;
I:整数;
列表,消息:TStringList;
开始
讯息:=nil;
尝试
列表:=TMyContext(AContext).OutgoingMessages.Lock;
尝试
如果List.Count>0,则
开始
消息:=TStringList.Create;
消息分配(列表);
列表。清晰;
结束;
最后
TMyContext(AContext).OutgoingMessages.Unlock;
结束;
如果消息为零,则
开始
对于I:=0到Messages.Count-1 do
开始
AContext.Connection.IOHandler.WriteLn(Messages.Strings[I]);
结束;
结束;
最后
信息。免费;
结束;
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
开始
AContext.Connection.IOHandler.checkforDataSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
出口
结束;
命令:=AContext.Connection.Socket.ReadLn;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-BEGIN');
如果命令为“”,则
开始
msSize:=AContext.Connection.Socket.ReadInt64;
ms:=TMemoryStream.Create;
解压缩DMS:=TMemoryStream.Create;
尝试
AContext.Connection.Socket.ReadStream(ms,msSize);
女士职位:=0;
解压流(MS,解压DMS);
解压DMS.位置:=0;
客户端处理数据(文本、命令、解压DMS);
最后
弗里女士;
解压dms.Free;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-END');
结束;
结束;
结束;
可以在已经运行的线程中运行代码吗?例如:thread1正在运行一些代码&我想在thread1中运行thread2中的代码

不需要。Thread1需要显式编码,以停止它当前正在执行的操作,执行其他操作,然后返回到以前的操作。Thread2所能做的就是向Thread1发出信号,让其尽早执行停止+继续操作


我想在idTCPServer线程中运行代码,以便向客户端发送一些数据

您的
TIdTCPServer.OnExecute
事件处理程序需要定期检查该数据,并在数据可用时发送

您可以使用
TIdContext.Data
属性,或从
TIdServerContext
派生自定义类,并将其分配给
tidcpserver.ContextClass
属性,为出站数据提供每客户端线程安全的缓冲区。然后,您的
OnExecute
处理程序可以在需要时访问该缓冲区

例如:

type
  TMyContext = class(TIdServerContext)
  public
    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
    destructor Destroy; override;
    OutgoingMessages: TIdThreadSafeStringList;
  end;

constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
begin
  inherited;
  OutgoingMessages := TIdThreadSafeStringList.Create;
end;

destructor TMyContext.Destroy;
begin
  OutgoingMessages.Free;
  inherited;
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
  // this must be set before activating the server...
  IdTCPServer1.ContextClass := TMyContext;
end;

procedure TMyForm.IdTCPServer1Execute(AContext: TIdContext);
var
  List, Messages: TStringList;
begin
  // check for outgoing data...

  Messages := nil;
  try
    List := TMyContext(AContext).OutgoingMessages.LockList;
    try
      if List.Count > 0 then
      begin
        Messages := TStringList.Create;
        Messages.Assign(List);
        List.Clear;
      end;
    finally
      TMyContext(AContext).OutgoingMessages.UnlockList;
    end;
    if Messages <> nil then
    begin
      // send Messages using AContext.Connection.IOHandler as needed...
    end;
  finally
    Messages.Free;
  end;

  // check for incoming data...

  if AContext.Connection.IOHandler.InputBufferIsEmpty then
  begin
    AContext.Connection.IOHandler.CheckForDataOnSource(100);
    AContext.Connection.IOHandler.CheckForDisconnect;
    if AContext.Connection.IOHandler.InputBufferIsEmpty then
      Exit;
  end;

  // process incoming data as needed...
end;

你能解释一下你到底想做什么吗?不太清楚。你的线程可以有多个过程,在你发送信号运行一个过程后,它可以运行任何代码。或者你可以
procedure TForm1.SomeProcedure;
var
  List: TIdContextList;
  Context: TMyContext;
begin
  List := IdTCPServer1.Contexts.LockList;
  try
    Context := TMyContext(List[SomeIndex]);
    Context.OutgoingMessages.Add('something');
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;
end;