加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

多线程 – 方法指针赋值线程是否安全?

发布时间:2020-12-14 16:24:57 所属栏目:Java 来源:网络整理
导读:例: 假设我会有以下线索(请不要考虑本例的线程上下文执行方法中使用的内容,仅供说明): type TSampleThread = class(TThread) private FOnNotify: TNotifyEvent; protected procedure Execute; override; public property OnNotify: TNotifyEvent read FOnN
例:

假设我会有以下线索(请不要考虑本例的线程上下文执行方法中使用的内容,仅供说明):

type
  TSampleThread = class(TThread)
  private
    FOnNotify: TNotifyEvent;
  protected
    procedure Execute; override;
  public
    property OnNotify: TNotifyEvent read FOnNotify write FOnNotify;
  end;

implementation

procedure TSampleThread.Execute;
begin
  while not Terminated do
  begin
    if Assigned(FOnNotify) then
      FOnNotify(Self); // <- this method can be called anytime
  end;
end;

然后假设,我想在任何时候我需要从主线程更改OnNotify事件的方法.这个主线程在这里实现了ThreadNotify方法的事件处理方法:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    FSampleThread: TSampleThread;
    procedure ThreadNotify(Sender: TObject);
  end;

implementation

procedure TForm1.ThreadNotify(Sender: TObject);
begin
  // do something; unimportant for this example
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FSampleThread.OnNotify := nil; // <- can this be changed anytime ?
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  FSampleThread.OnNotify := ThreadNotify; // <- can this be changed anytime ?
end;

题:

可以随时更改一个可以从另一个线程上下文的工作线程调用的方法吗?做上述例子所示的安全性是否安全?

我不是很确定,如果这是绝对安全的,至少由于方法指针实际上是一对指针,我不知道我是否可以把它当作一个原子操作.

解决方法

不,这不是线程安全的,因为这个操作永远不会是“原子的”. TNotifyEvent由两个指针组成,这些指针将不会同时被分配:一个指针将被分配,另一个将被分配.

为TNotifyEvent分配生成的32位汇编器由两个不同的汇编器指令组成,如下所示:

MOV [$00000000],Object
MOV [$00000004],MethodPointer

如果它是单个指针,那么您将有一些选项,因为该操作是原子的:您所选择的选项取决于CPU的内存模型的强大程度:

>如果CPU支持“顺序一致性”模式,则写入内存后发生的任何读取将会看到新的值.如果是这样,你可以简单地写下你的价值,不需要内存障碍或使用联锁方法.
>如果CPU更轻松地重新订购商店和装载,那么您需要一个“内存障碍”.如果是这样,最简单的解决方案是使用InterlockedExchangePointer

不幸的是,我不知道当前英特尔CPU的内存模型有多强大.有一些间接证据表明可能会发生一些重新排序,那些使用Interlock的可能会被推荐,但是我没有看到英特尔的一个或另一个的明确声明.

证据:

>现代CPU使用“预取” – 这意味着某种程度的加载/存储重新排序.> SSE介绍了处理CPU缓存的具体说明.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读