Delphi - 多线程:为什么我无法在 thread.terminate() 之后再次启动线程?

Delphi - Multithreading: Why I can't start thread again after thread.terminate()?

我编写了一个 multithread 应用程序来发送和接收 TCP 数据包。我遇到的问题是,当我两次调用下面代码的事件 confirmBoxRecognized(peerIP: string) 时。我收到以下异常:

Cannot call Start on a running or suspended thread

如果我检查线程对象,我有 terminated == truesuspended == false。为什么我编码错误?

代码如下:

TThreadReadTCP = class(TThread)

  private

    context: TfrmBoxTest;
    looping: Boolean;

    procedure readTCP;
  protected
    procedure DoTerminate; override;
    procedure Execute; override;

  public
    peerIP: String;
    responseObject: TProtocolObject;

    constructor Create(CreateSuspended: Boolean; ctx: TFrmBoxTest); overload;


  end;


{ TThreadReadTCP }

constructor TThreadReadTCP.Create(CreateSuspended: Boolean; ctx: TFrmBoxTest);
begin
  inherited Create(CreateSuspended);
  Self.context := ctx;
  FreeOnTerminate := True;
end;


procedure TThreadReadTCP.DoTerminate;
begin

  looping := false;
  inherited DoTerminate();

end;

procedure TThreadReadTCP.Execute;
begin
  inherited;
  looping := true;
  readTCP;
end;

procedure TThreadReadTCP.readTCP;
var
  buffer: TBytes;
begin

  while looping do
  begin

    if context.tcpClientBox.Connected then
    begin

      try

        buffer := TEncoding.ASCII.GetBytes(context.tcpClientBox.Socket.ReadLn());

        //do something else

      except on E:Exception  do
        ShowMessage('Error receiving TCP buffer with message: ' + e.Message);
      end;

    end;

  end;

end;



procedure TfrmBoxTest.confirmBoxRecognized(peerIP: string);
begin
  if (connectBoxTCP(peerIP)) then
  begin
    if Assigned(threadReadTCP) then
    begin
      threadReadTCP.Terminate();
      threadReadTCP.Start(); // I get the exception here when I run this code twice...
    end;
    showBoxRecognized();
  end;
  sendBoxRecognized();
end;

有运行线程状态可以获取吗?或者任何人都可以解释我如何改进这段代码来解决这个问题?

非常感谢!

您得到异常是因为您只能在 TThread 对象上调用 Start() 一次。线程启动后,您将无法重新启动它。一旦发出终止信号,您所能做的就是等待它完成终止,然后销毁该对象。

如果你想启动另一个线程运行,你必须创建一个新的TThread对象,例如:

type
  TThreadReadTCP = class(TThread)
  private
    context: TfrmBoxTest;
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    peerIP: String;
    responseObject: TProtocolObject;
    constructor Create(ctx: TFrmBoxTest); reintroduce;
  end;

constructor TThreadReadTCP.Create(ctx: TFrmBoxTest);
begin
  inherited Create(False);
  Self.context := ctx;

  // NEVER use FreeOnTerminate=True with a thread object that you keep a reference to!
  // FreeOnTerminate := True;
end;

procedure TThreadReadTCP.Execute;
var
  buffer: TBytes;
begin
  while not Terminated do
  begin
    try
      buffer := TEncoding.ASCII.GetBytes(context.tcpClientBox.Socket.ReadLn());
      // do something else
    except
      on E: Exception do
      begin
        // do something
        raise;
      end;
    end;
  end;
end;

procedure TThreadReadTCP.TerminatedSet;
begin
  try
    context.tcpClientBox.Disconnect(False);
  except
  end;
end;

...

procedure TfrmBoxTest.confirmBoxRecognized(peerIP: string);
begin
  if Assigned(threadReadTCP) then
  begin
    threadReadTCP.Terminate();
    threadReadTCP.WaitFor();
    FreeAndNil(threadReadTCP);
  end;
  if connectBoxTCP(peerIP) then
  begin
    threadReadTCP := TThreadReadTCP.Create(Self);
    showBoxRecognized();
  end;
  sendBoxRecognized();
end;