【问题标题】:Show file system tree data in TVirtualStringTree在 TVirtualStringTree 中显示文件系统树数据
【发布时间】:2015-11-11 05:32:50
【问题描述】:

我有这样的文件系统对象的线程安全类:

type
  PFSObject = ^TFSObject;
  TFSObject = class
  private
    FMREW: TMREWSync;

    FChildren: TObjectList<TFSObject>;
    FFilesCount: UInt32;
    FFoldersCount: UInt32;
    FName: string;
    FParent: TFSObject;

    function GetFullPath: string;
  public
    constructor Create(const AName: string; AParent: TFSObject; AFilesCount, AFoldersCount: UInt32 = 0);
    destructor Destroy; override;

    property Children: TObjectList<TFSObject> read FChildren write FChildren;
    property FilesCount: UInt32 read FFilesCount write FFilesCount;
    property FoldersCount: UInt32 read FFoldersCount write FFoldersCount;
    property Name: string read FName write FName;
    property Parent: TFSObject read FParent write FParent;

    procedure LockRead;
    procedure LockWrite;
    procedure UnlockRead;
    procedure UnlockWrite;
  end;

有线程,它扫描文件系统并填充它。 主窗体上有 Timer,它从这个类接收数据以显示在 TVirtualStringTree 中。

在 TVirtualStringTree 中显示此类数据且不会丢失额外内存以在节点中存储数据副本的最佳方法是什么?

更新: 好的,我现在拥有的。

type
  PSizeData = ^TSizeData;
  TSizeData = record
    FSObj: PFSObject;
  end;

// OnTimer reader
procedure TformSize.tmrSizeTimer(Sender: TObject);
begin
  if tvSize.RootNodeCount = 0 then
    tvSize.RootNodeCount := 1
  else begin
    tvSize.Repaint;
    if FSThread.Finished then begin
      // Thread finished, disable timer
      SetTimerEnabled(False);
      // Expant first node
      tvSize.Expanded[tvSize.GetFirst] := True;
    end;
  end;
end;

// GetText of TVirtualStringTree
procedure TformSize.tvSizeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType; var CellText: string);
var
  Data, ParData: PSizeData;
begin
  // Check that children count changed for node
  Data := tvSize.GetNodeData(Node);
  if (Int32(Node.ChildCount) <> Data.FSObj.Children.Count) then begin
    tvSize.ChildCount[Node] := Data.FSObj.Children.Count;
    // Check that children count changed for parent node
    ParData := tvSize.GetNodeData(Node.Parent); 
    if Assigned(ParData) and (Int32(Node.Parent.ChildCount) <> ParData.FSObj.Children.Count) then
      tvSize.ChildCount[Node.Parent] := ParData.FSObj.Children.Count;
  end;
  // Get node text
  CellText := GetSizeDataText(Data, Column);
end;

// InitNode of TVirtualStringTree
procedure TformSize.tvSizeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
  var InitialStates: TVirtualNodeInitStates);
var
  Data, ParData: PSizeData;
  PFSObj: PFSObject;
begin
  Data  := Sender.GetNodeData(Node);
  if not Assigned(ParentNode) then
    PFSObj := @FSThread.FSObject
  else begin
    ParData := Sender.GetNodeData(ParentNode);
    PFSObj := PFSObject(ParData.FSObj.Children[Node.Index]);
  end;
  Data.FSObj := PFSObj;
end;

现在我的 TVirtualStringTree 内存不足 :( 我的错误在哪里?

【问题讨论】:

  • 你说“线程安全”,但没有证据。
  • 这是课程的一小部分,没有用于阅读和写作的关键部分,仅作为示例。当然,上面的类不是线程安全的
  • 很难在没有任何线程安全细节的情况下就如何在多线程场景中使用类型提供建议。这些方面很可能相互作用。预期用途会影响线程安全设计。您当前的线程安全实现很可能不适合您的应用程序。
  • 在课堂上添加了我的读写实现。类的所有字段都在 LockRead/UnlockRead、LockWrite/UnlockWrite 对中使用
  • 所以你可以有多个读者,但只有一个作家?当有作家时,就没有读者了吗?啊,是的,我看到了TMREWSync

标签: multithreading delphi virtualtreeview tvirtualstringtree


【解决方案1】:

这肯定是VCL主线程和文件读/写线程之间的线程问题。

使用 VCL 时(记住:TVirtualStringTree 是一个 VCL 组件)您需要将额外的线程与 VCL 主线程同步。

我过去为避免此类问题所做的工作:

  1. 在 VCL 主线程(也就是你的 TForm 之类的)中创建一个互斥锁
  2. 创建线程并将互斥体传递给它
  3. 运行线程并在访问 VCL 属性时执行互斥锁之前和之后互斥解锁
  4. 在 VCL 主线程中也执行互斥锁/解锁

在没有安全同步的情况下,您绝不应该从其他线程访问或更改 VCL 属性。

【讨论】:

    猜你喜欢
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多