2017-08-01 9 views
0
interface 

type 

TMulticastListenerThread = class(TThread) 
strict private 
    ..... 
    _queue: TQueue<string>; 
    FOnReceive: TGetStrProc; 
    procedure DoReceive(); 
    ..... 
public 
    ..... 
    procedure Execute(); override; 
    property OnReceive:TGetStrProc read FOnReceive write FOnReceive; 
    ..... 
end; 

implementation 

procedure TMulticastListenerThread.Execute(); 
var addrlen: Integer; 
    nbytes: Integer; 
    msgbuf: array[1..MSGBUFSIZE] of AnsiChar; 
    msgstr: AnsiString; 
begin 
    inherited; 
    // now just enter a read-print loop 
    while not Terminated do begin 
    try 
     if not _connected then begin 
     Sleep(100); 
     continue; 
     end; 
     addrlen := sizeof(addr); 
     nbytes := recvfrom(fd, msgbuf, MSGBUFSIZE, 0, addr, addrlen); 
     if (nbytes < 0) then begin 
     perror('recvfrom'); 
     end 
     else begin 
     SetLength(msgstr, nbytes); 
     Move(msgbuf, PAnsiChar(msgstr)^, nbytes); 
     _queue.Enqueue(msgstr); 
     Synchronize(DoReceive); 
     end; 
    except 
     on ex: Exception do perror(ex.Message); 
    end; 
    end; 
end; 

すべては同期化されたDoReceiveメソッドです。デキューをプロシージャパラメータとして使用すると、TQueueが空になることはありません。

それは、このようなコードが含まれている場合:私は自分のアプリケーションを終了した後、それが何度も何度もwhileループを通過

procedure TMulticastListenerThread.DoReceive(); 
begin 
    while _queue.Count > 0 do 
    if Assigned(FOnReceive) then FOnReceive(_queue.Dequeue()); 
end; 

を、_queue.Countは "新しい文字列がをエンキューされていないものの、常に1あり、そしてTMulticastListenerThreadデストラクタは決して呼び出されません。

私は変数中間ローカル文字列によってデキュー:

procedure TMulticastListenerThread.DoReceive(); 
var s: string; 
begin 
    while _queue.Count > 0 do begin 
    s := _queue.Dequeue(); 
    if Assigned(FOnReceive) then FOnReceive(s); 
    end; 
end; 

アプリケーションが正常に終了し、デストラクタが呼び出されています。

これを説明できますか?

+1

割り当て済み(FOnReceive)がtrueを返す場合、最初の方法ではキューがクリアされ、いずれの場合も2番目の方法でキューがクリアされます。 –

答えて

3

_queue.Dequeue()は、FOnReceiveイベントハンドラを割り当てた場合にのみ実行されます。

procedure TMulticastListenerThread.DoReceive(); 
begin 
    while _queue.Count > 0 do 
    if Assigned(FOnReceive) then FOnReceive(_queue.Dequeue()); 
end; 

しかし、このコードは、あなたの割り当てチェックする前に、毎回_queue.Dequeue()呼び出します。

procedure TMulticastListenerThread.DoReceive(); 
var s: string; 
begin 
    while _queue.Count > 0 do begin 
    s := _queue.Dequeue(); 
    if Assigned(FOnReceive) then FOnReceive(s); 
    end; 
end; 
+0

あなたは正しいです。今私は何が起こっているのか理解しています。破壊すると、FOnReceiveは割り当て解除され、キューは決して空になりません。私はもっ​​と眠るべきです。 – Paul

+0

私たちは皆もっと眠る必要があります:) –

関連する問題