【问题标题】:Are private fields in a global instance thread safe全局实例线程中的私有字段是否安全
【发布时间】:2020-01-15 02:44:00
【问题描述】:

我有一个如下形状的类

TParser = class

private

  FFlag : boolean;
  FIntermediateValue : double;

  procedure F1(var aPartOfInput : string);
  procedure F2(var aSmallerPartOfInput : string) ;

public
  function Parse(const anInput : string): double;

end;

function TParser.Parse(const anInput : string) : double;
var
  aPartOfInput : string;
begin

  { Do some checks on the input and set FFlag to true/false.
    Set aPartOfInput to a piece of the input}
  f1(aPartOfInput);
  Result := FIntermediateValue;
end;

procedure TParser.F1(var aPartOfInput : string);
begin
  { Slice some more off the input.
    Set the FIntermediateValue }
  f2(aPartOfInput)
end;

procedure TParser.F2(var aSmallerPartOfInput : string);
begin
  { Depending on the input and FFlag, update FIntermediateValue }
end;

我们目前通过系统创建/销毁其中的一个 squillion(技术术语)。

我正在考虑创建一个实例并从每个位置调用它。

这个单一实例将从多个线程中调用。
使用私有字段是否意味着这不是线程安全的?

如果这不是线程安全的,我有哪些选项可以使它成为线程安全的?

编辑 - 选项

感谢所有cmets。

每个线程都有一个单独的实例

听起来不错,但由于代码的结构方式,实例需要对线程是“全局的”,没有办法(据我所知)将实例注入对象图到需要的地方(目前,在需要的地方创建解析器的新实例)

threadvar
    TheParser : TParser;

似乎是给我这个的一种方式。当我们启动线程时创建实例并在离开时释放它。这有什么问题吗?

摆脱实例变量

如果我们重新设计解析器,让它成为一个函数而不是一个类的实例,并且所有的值都被传递,这会让它成为线程安全的吗?

interface

function Parse(const anInput : string): double;

implementation

function F2(var aSmallerPartOfInput : string; theFlag : boolean; theIntermediateValue : double) : double ;
begin
  { update theIntermediateValue based on flag and input }
  Result := theIntermediateValue;
end;

function F1(var aPartOfInput : string; theFlag : boolean) : double;
var
  anIntermediateValue : double;
begin
  { Slice some more off the input
    Set the FIntermediateValue }
  Result := f2(aPartOfInput, theFlag, anIntermediateValue)
end;

function Parse(const anInput : string) : double;
var
  aPartOfInput : string;
  aFlag : boolean;
begin

  { set aFlag
    set aPartOfInput to a piece of the input }
  Result := f1(aPartOfInput, aFlag);
end;

【问题讨论】:

  • 定义线程安全?上面代码中的上下文太少,但是如果有不同的线程访问私有字段(读取和写入),即使它们是通过对象实例执行此操作,那么此代码不是线程安全的。 What is thread safety anyway?
  • 一切都将调用公共 Parse() 函数,在幕后没有任何工作。我担心说,在线程 1 上我们调用 Parse() 并且 FFlag 设置为 true,然后在线程 2 上我们调用 Parse() 并且 FFlag 设置为 false,然后返回线程 1 F2() 使用 false 值。我不知道这是否有可能
  • 需要序列化访问Parse
  • ...或为每个线程创建一个单独的解析器实例...
  • 使某些东西成为线程安全的最简单方法是为每个执行线程设置不同的实例。单个全局实例基本上是线程安全的敌人。

标签: multithreading delphi


【解决方案1】:

不,他们不是。

如果你想在不同的线程中使用同一个对象实例,你必须同步访问。

在 Windows 上只需使用临界区 (TRTLCriticalSection),在 posix 操作系统上使用互斥锁 (pthread_mutex_t)

您始终可以选择将您的类设计为幂等的,因此您可以在每个线程中拥有它的一个实例,然后在其中使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 2012-01-07
    • 2015-10-31
    相关资源
    最近更新 更多