如果将 Dequeue 用作过程参数,则 TQueue 永远不会被清空

TQueue gets never emptied if Dequeue used as a procedure parameter

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 方法的。

如果包含这样的代码:

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

在我终止我的应用程序后,它一次又一次地经历 while 循环,_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;

应用程序正常终止,正在调用析构函数。

你能解释一下吗?

在下面的代码中,_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;