Multithreading 在Delphi线程之间共享本机变量

Multithreading 在Delphi线程之间共享本机变量,multithreading,delphi,shared-variable,Multithreading,Delphi,Shared Variable,我假设,如果线程之间的共享变量具有本机类型,原子性应该完成这项工作 但根据下面代码的输出,情况并非如此,至少对于delphi是如此 线程t1只是简单地将计数器增加10倍。 同时,线程t2将计数器递减10倍。 所以末尾的预期计数器值是0,但我每次读取的值不同 在Delphi中,在线程之间共享本机变量而不锁定的正确方法是什么 procedure TForm1.Button1Click(Sender: TObject); var t1, t2: TThread; Counter: Native

我假设,如果线程之间的共享变量具有本机类型,原子性应该完成这项工作

但根据下面代码的输出,情况并非如此,至少对于delphi是如此

线程t1只是简单地将计数器增加10倍。 同时,线程t2将计数器递减10倍。 所以末尾的预期计数器值是0,但我每次读取的值不同

在Delphi中,在线程之间共享本机变量而不锁定的正确方法是什么

procedure TForm1.Button1Click(Sender: TObject);
var
  t1, t2: TThread;
  Counter: NativeInt;
begin
  Counter := 0;

  // first thread to increment shared counter
  t1 := TThread.CreateAnonymousThread(
    procedure ()
    var
      i: Integer;
    begin
      for i := 1 to 10000000 do
        Inc(Counter);
    end
  );

  // second thread to decrement shared counter
  t2 := TThread.CreateAnonymousThread(
    procedure ()
    var
      i: Integer;
    begin
      for i := 1 to 10000000 do
        Dec(Counter);
    end
  );

  t1.FreeOnTerminate := false;
  t2.FreeOnTerminate := false;

  // start threads
  t1.Start;
  t2.Start;

  // wait for them to finish
  t1.WaitFor;
  t2.WaitFor;

  t1.Free;
  t2.Free;

  // print the counter, expected counter is 0
  Caption := IntToStr(Counter);
end;

对齐变量的读写是原子的。但问题是,当你使用
inc
dec
时,你既在读也在写。通过执行两次内存访问,复合操作不再是原子操作

改用原子增量函数。
TInterlocked
类方法,或
AtomicIncrement


就本机而言,
NativeInt
,指的是它的大小。它是与指针大小相同的整数类型。32位进程中有32位,64位进程中有64位。这些类型很少用于纯Delphi代码,通常用于与第三方库的互操作,第三方库可能使用指针大小的整数声明句柄类型

我想这就是System.SyncObjs中的
TInterlocked
的目的。我已经检查了AtomicIncrement是如何在Delphi中实现的。它使用“lock xadd[eax],edx”。而不是使用Inc()和Dec()函数,TInterlocked.Increment(计数器)和TInterlocked.decreation(计数器)解决了这个问题。但NativeInt不被接受为输入类型,我不得不将其更改为整数。谢谢。我怀疑您是否有任何理由在执行的变量中使用NativeIntarithmetic@MehmetFide:
NativeInt
根据平台架构映射到
Integer
Int64
TInterlocked.Increment()
TInterlocked.Decrement()
对这两种类型都有重载,但是它们的参数声明为
var
,因此除非键入强制转换,否则无法传递
NativeInt
变量。但是,对非指针算术运算使用
NativeInt
通常是没有意义的。