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

Delphi中向辅助线程传递TStrings对象的方法

传递堆分配TStrings对象地址给Win32线程的实现示例

核心要点

  • 堆分配的TStrings(如TStringList)生命周期由调用者控制,只要线程运行期间对象不被释放,即可安全访问。
  • CreateThread的lpParameter参数可直接传递对象指针(或包含指针的自定义结构),进程内线程共享虚拟地址空间,指针有效。
  • 必须提前设置IsMultiThread := True,让VCL内存管理器切换到多线程安全模式。
  • TStrings并非线程安全,跨线程访问时需用同步机制(如临界区、事件)保护。

完整代码示例

unit ThreadStringsDemo;

interface

uses
  Windows, Classes, SysUtils;

implementation

// 工作线程函数:等待唤醒信号,操作TStrings对象
function WorkerThread(lpParameter: LPVOID): DWORD; stdcall;
type
  TThreadParams = record
    TargetStrings: TStrings;
    WakeEvent: THandle;
    AccessCS: TRTLCriticalSection; // 用于TStrings的线程同步
  end;
var
  Params: ^TThreadParams;
begin
  Params := lpParameter;
  try
    while True do
    begin
      case WaitForSingleObject(Params^.WakeEvent, INFINITE) of
        WAIT_OBJECT_0:
          begin
            ResetEvent(Params^.WakeEvent);
            // 临界区保护TStrings访问
            EnterCriticalSection(Params^.AccessCS);
            try
              Params^.TargetStrings.Add(Format('Thread updated at %s', [DateTimeToStr(Now)]));
            finally
              LeaveCriticalSection(Params^.AccessCS);
            end;
          end;
        WAIT_FAILED:
          begin
            OutputDebugString('WaitForSingleObject failed');
            Break;
          end;
      end;
    end;
  finally
    Dispose(Params);
  end;
  Result := 0;
end;

procedure DemoThreadStringPassing;
var
  WorkerStrings: TStrings;
  ThreadHandle: THandle;
  ThreadID: DWORD;
  Params: ^TThreadParams;
  WakeEvent: THandle;
  AccessCS: TRTLCriticalSection;
begin
  // 启用VCL多线程内存管理器
  IsMultiThread := True;

  // 初始化临界区
  InitializeCriticalSection(AccessCS);
  try
    // 创建堆上的TStrings对象
    WorkerStrings := TStringList.Create;
    try
      // 创建唤醒事件(手动重置,初始无信号)
      WakeEvent := CreateEvent(nil, True, False, nil);
      if WakeEvent = 0 then
      begin
        Writeln('Failed to create wake event');
        Exit;
      end;
      try
        // 分配线程参数(堆分配,避免栈变量生命周期问题)
        New(Params);
        Params^.TargetStrings := WorkerStrings;
        Params^.WakeEvent := WakeEvent;
        Params^.AccessCS := AccessCS;

        // 创建工作线程
        ThreadHandle := CreateThread(nil, 0, @WorkerThread, Params, 0, ThreadID);
        if ThreadHandle = 0 then
        begin
          Writeln('Failed to create worker thread');
          Dispose(Params);
          Exit;
        end;
        try
          // 调用端交互逻辑:触发线程更新或退出
          Writeln('Press Enter to trigger thread update; type "quit" to exit');
          while True do
          begin
            var InputLine: string;
            Readln(InputLine);
            if UpperCase(InputLine) = 'QUIT' then
              Break;

            // 触发线程执行更新
            SetEvent(WakeEvent);

            // 安全读取TStrings内容(临界区保护)
            EnterCriticalSection(AccessCS);
            try
              Writeln('Current string count: ', WorkerStrings.Count);
              for var I := 0 to WorkerStrings.Count - 1 do
                Writeln('  ', WorkerStrings[I]);
            finally
              LeaveCriticalSection(AccessCS);
            end;
          end;

          // 终止线程(实际项目建议用优雅退出标志,TerminateThread为简化示例)
          TerminateThread(ThreadHandle, 0);
        finally
          CloseHandle(ThreadHandle);
        end;
      finally
        CloseHandle(WakeEvent);
      end;
    finally
      WorkerStrings.Free;
    end;
  finally
    DeleteCriticalSection(AccessCS);
  end;
end;

end.

关键细节说明

  1. 参数传递方式:示例用堆分配的TThreadParams结构传递多个参数(TStrings指针、唤醒事件、临界区),如果仅需传递TStrings,可直接将WorkerStrings作为lpParameter传入,线程函数内转换为TStrings(lpParameter)即可。
  2. 线程安全保护:通过临界区TRTLCriticalSection确保调用者和线程不会同时修改/读取TStrings,避免数据损坏。
  3. 对象生命周期:TStrings对象由调用者创建和释放,线程仅负责访问,需保证线程运行期间对象不被提前释放。
  4. 线程唤醒逻辑:用CreateEvent创建的事件控制线程唤醒,符合“无限等待填充”的需求,调用者通过SetEvent触发线程执行更新操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 10:40:25