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

时间:2018-04-23 20:01:19

标签: multithreading delphi delphi-xe3

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

  

无法在正在运行或已挂起的线程上调用Start

如果我签入了线程对象,那我就是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;

我可以获得正在运行的线程状态吗?或者任何人都可以解释如何改进此代码来解决这个问题?

非常感谢!

1 个答案:

答案 0 :(得分:4)

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

如果您希望另一个线程开始运行,您必须创建一个新的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;