【问题标题】:Multithread - How to make timeout and how to make "interlocking"?多线程 - 如何进行超时以及如何进行“互锁”?
【发布时间】:2014-11-26 21:33:06
【问题描述】:

我有一个线程。在它们内部,我有一个循环来发送 UDP 数据包。在这个循环中,我需要在发送下一条消息之前等待设备的 UDP 响应(接收到上一个数据包 [如果 OK 与否])。如果 OK 我发送 StringList 的下一条消息,如果错误我停止线程。怎么做?我还需要更多:如果软件没有收到设备的响应,我需要实现 3 秒的超时。

我正在使用 TIdUDPServer 来监听 udp 包。

这是我的代码:

TEnvioFirmware = class(TThread)
  private
    I: integer;
    Lock: TCriticalSection;
    mMac: string;
    mVersao: integer;
    mProduto: integer;
    _max: integer;
    _min: integer;
    mIP: string;
    firmware_string: TStringList;
    idpclnt: TIdUDPClient;
    progress: TProgressBar;
    lbPorc: TLabel;
    bAck: Boolean;
    procedure Executar;
    procedure OnVerificarTimeOut(Sender: TObject);
  public
    tmrTimeout: TTimer;
    bContinua: Boolean;
    procedure Execute; override;
    constructor Create(CreateSuspended: Boolean; firmware_string: TStringList;
      edtIP: string; idpclnt: TIdUDPClient; max, atual: integer;
      var pb: TProgressBar; var lblPorcentagem: TLabel; abAck: Boolean);

  end;

procedure TEnvioFirmware.Execute;
begin
  inherited;
  // Synchronize(Executar);
  Executar;
end;

procedure TEnvioFirmware.Executar;
var
  I, J: integer;
  X: pacote;
  Y: String;
  B: String;
  B2: String;
  msgCount: integer;
  Buffer: TBytes;
  // array[0..5] of Byte;
  max, atual: integer;
  BufferSend: TBytes;
begin

  SetLength(Buffer, 6);

  idpclnt.Host := mIP;
  idpclnt.Active := true;
  msgCount := firmware_string.Count;
  max := msgCount - 1; // Progress Bar
  // pb.Max := max;
  self.progress.Min := 0;
  self.progress.max := max;

  B := '12345';
  B2 := '0';

  if bAck then
  begin           //trying to make timeout
    tmrTimeout := TTimer.Create(nil);
    tmrTimeout.Interval := 3000;
    tmrTimeout.OnTimer := OnVerificarTimeOut;
  end;

  bContinua := True;


  for I := 0 to msgCount - 1 do
  begin

    B[1] := chr(15);
    B[2] := chr(0);
    B[3] := chr(2);
    B[4] := chr((I) mod 256);
    B[5] := chr((I) div 256);

    B2[1] := chr(255);

    Y := B + firmware_string.Strings[I] + B2;

    SetLength(BufferSend, Length(Y));

    for J := 0 to Length(BufferSend) - 1 do
    begin

      BufferSend[J] := Ord(Y[J + 1]);

    end;



    if bContinua then
      idpclnt.SendBuffer(BufferSend);  //after send the device will response

    if not bAck then
    begin
      Sleep(200);
      bContinua := true;
      progress.Position := I + 1;
      lbPorc.Caption :=
        IntToStr(Round((100 * progress.Position) / progress.max));
      atual := I;
    end
    else
    begin

      tmrTimeout.Enabled := True;

    end;

  end;

  Buffer[0] := $0F;
  Buffer[1] := 00;
  Buffer[2] := 03;
  Buffer[3] := (msgCount) mod 256;
  Buffer[4] := (msgCount) div 256;
  Buffer[5] := 255;

  idpclnt.SendBuffer(Buffer);

  Sleep(150);

end;

在 UDP 读取时

if (AData[0] = 15) and (AData[1] = 1) and (AData[2] = 2) and (Count = 5)
  then
  begin

    if AData[3] = 0 then
    begin
      MainEstrutura.objFirmwareUpdater.bContinua := true;
      MainEstrutura.objFirmwareUpdater.tmrTimeout.Enabled := false;
    end
    else
    begin
      MainEstrutura.objFirmwareUpdater.bContinua := false;
      MainEstrutura.objFirmwareUpdater.tmrTimeout.Enabled := false;
    end;

  end;

【问题讨论】:

  • “我尝试了很多”意味着您应该至少尝试一次,您可以将其包含在您的帖子中。可以请edit添加吗?
  • 我发布了。够了吗?
  • UI 控件在您的线程内?我根本看不到这有什么作用。
  • 如果没有消息泵来处理 Windows 消息,计时器也无法工作。

标签: multithreading delphi delphi-7 indy


【解决方案1】:

由于您需要序列化您的数据包,您应该在线程内部使用TIdUDPClient,而不是在线程外部使用TIdUDPServer。然后,您根本不必处理同步 OnUDPRead 事件或使用计时器。只需让线程SendBuffer() 发出一个传出数据包,然后立即ReceiveBuffer() 指定超时的入站响应,并根据需要继续循环直到完成。如果超时,根据您的需要重新发送出站数据包或终止线程。

在这种情况下使用TIdUDPServer 的唯一原因是,如果您有多个固件线程同时运行并且它们都响应相同的 IP/端口,在这种情况下使用单个 @ 是有​​意义的987654327@ 接收所有这些响应并根据需要将它们委托给每个适当的固件线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    • 1970-01-01
    • 2010-12-29
    • 2021-04-20
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多