You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi2007 Indy9下IdThreadComponent调用TThread.Queue编译报错求助

问题根因

编译报错、数据丢失的核心原因非常明确:

  • Delphi 2007 是早于匿名方法特性发布的版本,匿名过程语法从Delphi 2009才正式支持,编译器无法识别TThread.Queue参数里内嵌的procedure结构,直接抛出语法错误。
  • Delphi 2007 自带的TThread.Queue仅支持传入无参数的对象方法(TThreadMethod类型),没有适配匿名过程的重载版本,即使跳过语法检查也无法正常运行。
  • 直接去掉同步逻辑在工作线程操作VCL控件,本身就违反VCL单线程访问规则,会随机出现访问冲突、写入覆盖,自然会丢数据。不要图省事直接在线程里写Memo1.Text := s,哪怕跑通几次也是隐患。
适配Delphi 2007 + Indy 9的实现方案

采用线程安全队列做中转,配合D2007原生支持的异步队列同步,既不阻塞读条码的工作线程,也不会丢数据:

  • 在窗体层维护一个字符串队列+临界区对象,做工作线程和UI线程的数据中转
  • 工作线程每次读到有效条码后,加锁将数据压入队列,再调用TThread.Queue触发UI同步,全程不阻塞读操作
  • UI线程执行同步方法时,一次性取出队列中所有缓存的条码逐个处理,避免单变量中转时新数据覆盖旧数据的问题
  • 注意核对Indy9版本ReadLn的参数顺序,Indy9和Indy10的部分重载参数顺序有差异,不要传反导致读超时、读截断

适配后的可直接运行的代码如下:

// 窗体类定义部分
type
  TPkgSendF1 = class(TForm)
    IdTCPClient1: TIdTCPClient;
    IdThreadComponent1: TIdThreadComponent;
    Memo1: TMemo;
    procedure IdThreadComponent1Run(Sender: TIdCustomThreadComponent);
  private
    FBarcodeQueue: TStringList;
    FQueueLock: TRTLCriticalSection;
    procedure SyncProcessBarcode;
    procedure ProcessRead(AValue: string);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

// 窗体实现部分
constructor TPkgSendF1.Create(AOwner: TComponent);
begin
  inherited;
  InitializeCriticalSection(FQueueLock);
  FBarcodeQueue := TStringList.Create;
end;

destructor TPkgSendF1.Destroy;
begin
  DeleteCriticalSection(FQueueLock);
  FBarcodeQueue.Free;
  inherited;
end;

procedure TPkgSendF1.IdThreadComponent1Run(Sender: TIdCustomThreadComponent);
var
  s: string;
begin
  // 注意核对Indy9下ReadLn的参数顺序,确保结束符、超时参数匹配版本定义
  s := IdTCPClient1.ReadLn('&', 20000, 1500);
  if s = '' then Exit; // 超时无有效数据直接返回,不压入空内容

  // 加锁将读到的条码压入安全队列
  EnterCriticalSection(FQueueLock);
  try
    FBarcodeQueue.Add(s);
  finally
    LeaveCriticalSection(FQueueLock);
  end;

  // D2007下Queue仅支持无参数对象方法,直接传入同步方法即可,异步执行不阻塞工作线程
  TThread.Queue(nil, SyncProcessBarcode);
end;

procedure TPkgSendF1.SyncProcessBarcode;
var
  tmpList: TStringList;
  i: Integer;
begin
  tmpList := TStringList.Create;
  try
    // 加锁一次性取出所有待处理数据,缩短锁持有时间,避免阻塞工作线程入队
    EnterCriticalSection(FQueueLock);
    try
      tmpList.AddStrings(FBarcodeQueue);
      FBarcodeQueue.Clear;
    finally
      LeaveCriticalSection(FQueueLock);
    end;

    // UI线程中逐个处理缓存的条码,无覆盖丢失问题
    for i := 0 to tmpList.Count - 1 do
    begin
      ProcessRead(tmpList[i]);
    end;
  finally
    tmpList.Free;
  end;
end;

procedure TPkgSendF1.ProcessRead(AValue: string);
begin
  // 所有UI操作都在主线程执行,无线程安全问题
  Memo1.Text := AValue;
end;

补充说明:不要用TThread.Synchronize替换TThread.Queue,Synchronize会阻塞工作线程直到UI方法执行完成,如果UI线程卡顿会直接导致条码读取超时丢数,Queue是异步排队执行,不会影响工作线程的读取效率。

内容的提问来源于stack exchange,提问作者FAlvarado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:49:12