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

Delphi中使用TMonitor控制全局对象访问的代码实现是否正确?

Delphi中TMonitor实现ReLoad阻塞GetWorker的正确性验证

核心结论

你基于TMonitor实现的阻塞逻辑是正确且符合Delphi线程同步最佳实践的,Wait和PulseAll的使用方式合理,能够确保ReLoad执行期间GetWorker被正确阻塞,直到缓存重建完成。

关键逻辑分析

结合你的描述,还原简化实现的核心结构如下:

type
  TWorker = class
    // 工作类业务逻辑定义
  end;

  IStorage = interface
    ['{YOUR-GUID-HERE}']
    function GetWorker(const WorkerID: string): TWorker;
    procedure ReLoad;
  end;

  TStorage = class(TInterfacedObject, IStorage)
  private
    fWorkers: TDictionary<string, TWorker>;
    fIsReloading: Boolean;
    procedure CleanupWorkers;
    procedure LoadFromDisk;
  public
    constructor Create;
    destructor Destroy; override;
    function GetWorker(const WorkerID: string): TWorker;
    procedure ReLoad;
  end;

{ TStorage }

constructor TStorage.Create;
begin
  inherited;
  fWorkers := TDictionary<string, TWorker>.Create;
  fIsReloading := False;
  LoadFromDisk;
end;

destructor TStorage.Destroy;
begin
  CleanupWorkers;
  fWorkers.Free;
  inherited;
end;

procedure TStorage.CleanupWorkers;
var
  Worker: TWorker;
begin
  for Worker in fWorkers.Values do
    Worker.Free;
  fWorkers.Clear;
end;

procedure TStorage.LoadFromDisk;
begin
  // 从XML读取定义并初始化TWorker实例到fWorkers
end;

procedure TStorage.ReLoad;
begin
  TMonitor.Enter(Self);
  try
    fIsReloading := True;
    try
      CleanupWorkers;
      LoadFromDisk;
    finally
      fIsReloading := False;
      TMonitor.PulseAll(Self);
    end;
  finally
    TMonitor.Exit(Self);
  end;
end;

function TStorage.GetWorker(const WorkerID: string): TWorker;
begin
  TMonitor.Enter(Self);
  try
    while fIsReloading do
      TMonitor.Wait(Self);
    if not fWorkers.TryGetValue(WorkerID, Result) then
      Result := nil; // 按实际业务逻辑处理未找到的情况
  finally
    TMonitor.Exit(Self);
  end;
end;

针对同步逻辑的细节验证:

  • 临界区保护:所有访问共享状态(fIsReloading、fWorkers)的代码都被TMonitor.Enter/Exit包裹,确保同一时间只有一个线程能修改或读取这些状态,避免并发冲突。
  • Wait的循环检查:GetWorker中使用while fIsReloading do TMonitor.Wait(Self)是正确的——Wait会临时释放锁,让ReLoad线程能进入临界区执行;被唤醒后再次检查fIsReloading,可以避免虚假唤醒(虽然Delphi TMonitor的虚假唤醒概率极低,但这是线程同步的标准最佳实践)。
  • PulseAll的触发时机:ReLoad在完成缓存重建、设置fIsReloading := False后调用PulseAll,能一次性唤醒所有等待的GetWorker线程,确保它们能及时感知到缓存已更新,继续执行逻辑。

额外注意事项

  1. 如果GetWorker中有动态创建TWorker的逻辑,必须确保这部分代码也在TMonitor的临界区内,避免和ReLoad的CleanupWorkers操作产生并发冲突。
  2. 全局TStorage实例的初始化和销毁要确保线程安全,避免在多线程环境下出现未初始化或重复销毁的问题。
  3. LoadFromDisk如果是耗时操作,当前实现会让ReLoad线程独占临界区直到完成,若想优化可考虑将磁盘读取逻辑移出临界区(但需注意新缓存的原子替换,比如用临时字典加载后再替换fWorkers),减少对GetWorker的阻塞时间。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 23:17:32