2014-11-26 3 views
-2

У меня есть нить. Внутри них у меня есть цикл для отправки пакета UDP. В этом цикле мне нужно подождать UDP-ответ устройства (который получил предыдущий пакет [если OK или нет]) перед отправкой следующего сообщения. Если ОК, отправьте следующее сообщение StringList, если ошибка прекратит поток. Как это сделать? И мне нужно больше: мне нужно реализовать тайм-аут в течение 3 секунд, если программное обеспечение не получит ответ устройства.Multithread - Как сделать тайм-аут и как сделать «блокировку»?

Я использую 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; 

На UDPRead

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; 
+1

«Я много пробовал» означает, что у вас должна быть хотя бы одна попытка, которую вы можете включить в свой пост. Не могли бы вы [изменить], чтобы добавить его? –

+0

Я отправил. Достаточно? –

+0

Пользовательский интерфейс контролирует вашу нить? Я не вижу возможности, как это может работать вообще. –

ответ

2

Так как вам нужно сериализовать ваши пакеты, вы должны использовать TIdUDPClient внутри нити вместо того, чтобы использовать TIdUDPServer вне резьбы , Тогда вам не придется иметь дело с синхронизацией события OnUDPRead или с использованием таймера вообще. Просто укажите поток SendBuffer() исходящий пакет, а затем сразу ReceiveBuffer() входящий ответ с указанным таймаутом и продолжайте цикл по мере необходимости до завершения. Если тайм-аут истекает, либо повторно отправляет исходящий пакет, либо завершает поток, в зависимости от ваших потребностей.

Единственная причина использования TIdUDPServer в этой ситуации - это одновременное выполнение нескольких потоков прошивки, и все они отвечают на один и тот же IP/порт, и в этом случае имеет смысл иметь один TIdUDPServer, принимающий все эти ответы и делить их на каждый соответствующий поток прошивки по мере необходимости.

Смежные вопросы