【问题标题】:Thread-safety in custom class when accessing FireMonkey component访问 FireMonkey 组件时自定义类中的线程安全
【发布时间】:2015-08-26 16:43:23
【问题描述】:

我正在编写一个自定义类,它应该能够连接到表单上的 TMemo FireMonkey 组件,以便将信息记录到其中。该类定义为:

TBlokData = class
private
  [weak] FLogMemo: TMemo;
  procedure Log(s : string);
public
  constructor Create(ConnStr: string);
  property LogMemo : TMemo read FLogMemo write FLogMemo;
  destructor Destroy; override;
end;

Log 方法的实现是:

procedure TBlokData.Log(s : string);
begin
    if Assigned(FLogMemo) then
        FLogMemo.Lines.Add(TimeToStr(Now) + ': ' + s);
end;

如果我在线程中创建类对象并使用 FireMonkey 表单上的 Memo1 组件填充 LogMemo 属性,我担心我的类将不再是线程安全的,因为我将操作调用Log 方法时,来自线程的窗体上的组件。

这是一个有效的担忧吗?如果是这样,我怎样才能使其线程安全,同时在线程环境之外保持类的可用性?

【问题讨论】:

    标签: delphi thread-safety


    【解决方案1】:

    创建一个方法LogThreadSafe:

      TThread.Synchronize(nil, procedure 
        begin
          Log(s);
        end); 
    

    【讨论】:

    • 同步没有检查线程ID吗?没有必要检查两次。
    • docwiki.embarcadero.com/Libraries/XE8/en/… : "警告: 不要在主线程中调用 Synchronize。这会导致无限循环。"
    • 那个文档是错误的。 TThread.Synchronize检查线程ID,如果我们在主线程上,它只是直接调用方法并返回。通过TThread.CurrentThread 有点无意义。最好通过nil
    • 感谢您指出这一点。你是对的。有时我觉得 Embarcadero 有两种文档:错误和缺失
    【解决方案2】:

    你的担心是对的。您的代码不是线程安全的。使用TThread.SynchronizeTThread.Queue 确保对UI 控件的任何操作都在主UI 线程上执行。

    一般来说,对 UI 组件的任何操作都必须在 UI 线程上执行。

    【讨论】:

    • 我应该如何执行在 UI 线程之外运行的后台任务?
    猜你喜欢
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多