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

时间:2017-08-01 08:04:47

标签: multithreading delphi thread-synchronization

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;

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

你能解释一下吗?

1 个答案:

答案 0 :(得分: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;