随笔 - 808  文章 - 0 评论 - 143 阅读 - 770万

unit System 单元下有这些函数

image

在System单元里 搜不到这些函数的具体定义,只可以这样智能提示看到;

另外在 System.SyncObjs 有一个TInterlocked的密封类,其十多个类函数(class function)其实都是调用的System单元的原子操作函数,只是封装得更容易理解。

  { TInterlocked implements various common atomic opererations for the purpose of ensuring "thread" or "multi-core"
    safety when modifying variables that could be accessed from multiple threads simultaneously. The TInterlocked class
    is not intended to be instantiated nor derived from. All the methods are "class static" and are merely defined in
    a class as a way to group their like-functionality.
  }
  {
    中文翻译:TInterlocked实现了各种常见的原子操作,以确保“线程”或“多核”
在修改可以从多个线程同时访问的变量时,可以确保其安全性。TInterlocked 类
  不是用来实例化的,也不是从它派生出来的。所有的方法都是“类静态的”,只是在
    将类作为将具有相似功能的事物进行分组的一种方式。
    ----------------------------------------------------
    可见这个 TInterLocked 只是官方的一个分组封装,方便你使用;
  }

  TBitOffset = 0..31;
  TBitOffset64 = 0..63;
  TInterlocked = class sealed
  public
    class function Increment(var Target: Integer): Integer; overload; static; inline;
    class function Increment(var Target: Cardinal): Cardinal; overload; static; inline;
    class function Increment(var Target: Int64): Int64; overload; static; inline;
    class function Increment(var Target: UInt64): UInt64; overload; static; inline;
    class function Decrement(var Target: Integer): Integer; overload; static; inline;
    class function Decrement(var Target: Cardinal): Cardinal; overload; static; inline;
    class function Decrement(var Target: Int64): Int64; overload; static; inline;
    class function Decrement(var Target: UInt64): UInt64; overload; static; inline;
    class function Add(var Target: Integer; Increment: Integer): Integer; overload; static; inline;
    class function Add(var Target: Cardinal; Increment: Cardinal): Cardinal; overload; static; inline;
    class function Add(var Target: Int64; Increment: Int64): Int64; overload; static; inline;
    class function Add(var Target: UInt64; Increment: UInt64): UInt64; overload; static; inline;
    class function BitTestAndSet(var Target: Integer; BitOffset: TBitOffset): Boolean; overload; static;
    class function BitTestAndSet(var Target: Cardinal; BitOffset: TBitOffset): Boolean; overload; static;
    class function BitTestAndSet(var Target: Int64; BitOffset: TBitOffset64): Boolean; overload; static;
    class function BitTestAndSet(var Target: UInt64; BitOffset: TBitOffset64): Boolean; overload; static;
    class function BitTestAndClear(var Target: Integer; BitOffset: TBitOffset): Boolean; overload; static;
    class function BitTestAndClear(var Target: Cardinal; BitOffset: TBitOffset): Boolean; overload; static;
    class function BitTestAndClear(var Target: Int64; BitOffset: TBitOffset64): Boolean; overload; static;
    class function BitTestAndClear(var Target: UInt64; BitOffset: TBitOffset64): Boolean; overload; static;
    class function Exchange(var Target: Pointer; Value: Pointer): Pointer; overload; static; inline;
    class function Exchange(var Target: Integer; Value: Integer): Integer; overload; static; inline;
    class function Exchange(var Target: Cardinal; Value: Cardinal): Cardinal; overload; static; inline;
    class function Exchange(var Target: Int64; Value: Int64): Int64; overload; static; inline;
    class function Exchange(var Target: UInt64; Value: UInt64): UInt64; overload; static; inline;
    class function Exchange(var Target: TObject; Value: TObject): TObject; overload; static; inline;
    class function Exchange(var Target: Single; Value: Single): Single; overload; static; inline;
    class function Exchange(var Target: Double; Value: Double): Double; overload; static; inline;
    class function Exchange(var Target: Boolean; Value: Boolean): Boolean; overload; static; inline;
    class function Exchange<T: class>(var Target: T; Value: T): T; overload; static; inline;
    class function CompareExchange(var Target: Pointer; Value: Pointer; Comparand: Pointer): Pointer; overload; static; inline;
    class function CompareExchange(var Target: Pointer; Value: Pointer; Comparand: Pointer; out Succeeded: Boolean): Pointer; overload; static; inline;
    class function CompareExchange(var Target: Integer; Value: Integer; Comparand: Integer): Integer; overload; static; inline;
    class function CompareExchange(var Target: Integer; Value: Integer; Comparand: Integer; out Succeeded: Boolean): Integer; overload; static;
    class function CompareExchange(var Target: Cardinal; Value: Cardinal; Comparand: Cardinal): Cardinal; overload; static; inline;
    class function CompareExchange(var Target: Cardinal; Value: Cardinal; Comparand: Cardinal; out Succeeded: Boolean): Cardinal; overload; static; inline;
    class function CompareExchange(var Target: Int64; Value: Int64; Comparand: Int64): Int64; overload; static; inline;
    class function CompareExchange(var Target: Int64; Value: Int64; Comparand: Int64; out Succeeded: Boolean): Int64; overload; static; inline;
    class function CompareExchange(var Target: UInt64; Value: UInt64; Comparand: UInt64): UInt64; overload; static; inline;
    class function CompareExchange(var Target: UInt64; Value: UInt64; Comparand: UInt64; out Succeeded: Boolean): UInt64; overload; static; inline;
    class function CompareExchange(var Target: TObject; Value: TObject; Comparand: TObject): TObject; overload; static; inline;
    class function CompareExchange(var Target: TObject; Value: TObject; Comparand: TObject; out Succeeded: Boolean): TObject; overload; static; inline;
    class function CompareExchange(var Target: Double; Value: Double; Comparand: Double): Double; overload; static; inline;
    class function CompareExchange(var Target: Double; Value: Double; Comparand: Double; out Succeeded: Boolean): Double; overload; static; inline;
    class function CompareExchange(var Target: Single; Value: Single; Comparand: Single): Single; overload; static; inline;
    class function CompareExchange(var Target: Single; Value: Single; Comparand: Single; out Succeeded: Boolean): Single; overload; static; inline;
    class function CompareExchange(var Target: Boolean; Value: Boolean; Comparand: Boolean): Boolean; overload; static; inline;
    class function CompareExchange(var Target: Boolean; Value: Boolean; Comparand: Boolean; out Succeeded: Boolean): Boolean; overload; static; inline;
    class function CompareExchange<T: class>(var Target: T; Value: T; Comparand: T): T; overload; static; inline;
    class function CompareExchange<T: class>(var Target: T; Value: T; Comparand: T; out Succeeded: Boolean): T; overload; static; inline;
    class function Read(var Target: Int64): Int64; overload; static; inline;
    class function Read(var Target: UInt64): UInt64; overload; static; inline;
  end;

使用方法:如对一个数值加一,则直接b:= TInterlocked.Increment(a);或TInterlocked.Increment(a);,不用创建TInterlocked类(类函数相当于就是单独的函数,可以直接调用,不用实例化对象)

大致就是4种,递增、递减、交换、比较交换;我们来一一研究测试一下;

递增、递减

procedure TForm2.btn1Click(Sender: TObject);
var
  i: Integer;
  i4: Int64;
begin
  i := 0;
  AtomicIncrement(i, 2);
  OutputDebugString(PChar(i.ToString));//2
  AtomicDecrement(i, 3);
  OutputDebugString(PChar(i.ToString));//-1


  i4 := 0;
  AtomicIncrement(i4, 2);
  OutputDebugString(PChar(i4.ToString)); //2
  AtomicDecrement(i4, 3);
  OutputDebugString(PChar(i4.ToString));//-1
end;

交换

procedure TForm1.btn1Click(Sender: TObject);
var
  i, r: Integer;
begin
  i := 0;
  r := AtoMicExchange(i, 2);
  OutputDebugString(PChar(i.ToString));// 2 被替换成了2
  OutputDebugString(PChar(r.ToString));// 0  返回的依然是旧值
end;

比较交换

有3个重载,Integer、Int64、Pointer

procedure TForm2.btn1Click(Sender: TObject);
var
  i, r: Integer;
  b: Boolean;
begin
  i := 0;
  r := AtomicCmpExchange(i, 2, 2, b);
  OutputDebugString(PChar(i.ToString));// 0 , 没有替换成功,i还是旧值
  OutputDebugString(PChar(r.ToString));// 0  返回的依然是旧值
  OutputDebugString(PChar(b.ToString(TUseBoolStrs.True)));// False

  OutputDebugString('----------------------------');

  i := 0;
  r := AtomicCmpExchange(i, 2, 0, b);
  OutputDebugString(PChar(i.ToString));// 2
  OutputDebugString(PChar(r.ToString));// 0 , 说明返回的还是原来的旧值
  OutputDebugString(PChar(b.ToString(TUseBoolStrs.True)));// True
end;

注意:不管是否替换成功,返回的都是“旧值"

image

读取

正常的读取不会存在多线程安全的问题,但是我们可以看到 TInterlocked 提供了 2个 Read函数,如下:

image

他们的实现代码如下:

class function TInterlocked.Read(var Target: Int64): Int64;
begin
  Result := CompareExchange(Target, 0, 0);
end;

class function TInterlocked.Read(var Target: UInt64): UInt64;
begin
  Result := CompareExchange(Target, 0, 0);
end;

为什么要提供出这2个Read函数呢,这是因为若你的程序是32位的,如:

image

直接在多线程里直接读取一个64位变量,寄存器是分为高字节和低字节两个部分,就是说会读取2次,如读取了低字节部分后,高字节部分被其他线程写,就会读到脏数据,用原子操作读取则不会,这确保了在读取 Target 变量的过程中不会被其他线程中断;

当然若你的程序是64位的话,则没有必要使用 TInterlocked.Read() 来读取 Int64或UInt64的整型,直接读取就可;32位程序读取Int64或UInt64才需要使用 TInterlocked.Read() 来确保多线程安全;

我们来分析一下,这个Read他是如何实现的:

class function TInterlocked.Read(var Target: Int64): Int64;
begin
  Result := CompareExchange(Target, 0, 0); //这里调用 CompareExchange
end;

class function TInterlocked.CompareExchange(var Target: Int64; Value, Comparand: Int64): Int64;
begin
  Result := AtomicCmpExchange(Target, Value, Comparand); // CompareExchange 又调用 AtomicCmpExchange
end;
//可见最终调用的是
Result := AtomicCmpExchange(Target, 0, 0);
{
  第一个0是新值,第二个0是比较值,意思是 若此时 tartget = 第二个0,然后就把tartget替换成第一个0,然后返回target原来的值;
  因为 AtomicCmpExchange 无论比较是否成功,最终都会返回 target的旧值;这么做而不是直接读取 Int64 仅仅是为了32位程序 读取
  Int64,这个函数很有意思:
  1. target <> 0 ,不替换,返回target原来的值;
  2. target = 0, 用0替换(和不替换没有分别),返回target原来的值(还是0);
  那这么做,有什么意义,我已经说了 仅仅是为了32位多线程程序安全读取 Int64和 UInt64;
  现在都是64位程序了,这个Read函数 基本无用途了;
}

寄存器知识

32位程序的寄存器是 几位,64位程序的寄存器是几位?

在计算机体系结构中,32位程序和64位程序的寄存器大小与其对应的位数相匹配。

  1. 32位程序:在32位体系结构中,整数寄存器、地址寄存器和大部分其他寄存器通常是32位宽。这意味着它们可以存储和处理的最大数值是2^32 - 1(约为42.9亿或4GB的地址空间,但实际上地址空间还要考虑到一些保留位和特殊用途的地址,因此实际上可用的内存会少于这个数)。
  2. 64位程序:在64位体系结构中,整数寄存器、地址寄存器和大部分其他寄存器是64位宽。这意味着它们可以存储和处理的最大数值是2^64 - 1(这是一个非常大的数,对于内存地址来说,这远远超过了现代个人计算机所需要的地址空间)。64位系统允许程序使用大量的内存(理论上是16 EB,但实际受到物理硬件和操作系统的限制)。

这些位数指的是CPU内部的寄存器大小,它们直接影响程序的运行方式和能够处理的数据量。此外,64位系统通常也兼容32位程序,但这通常需要一些额外的软件支持(如操作系统和运行时库的支持)。在64位系统上运行32位程序时,该程序的寄存器将模拟32位寄存器的行为。


寄存器的大小与 程序的位数有关?

是的,寄存器的大小与程序的位数是直接相关的。寄存器是CPU内部用于暂时存储数据的小块内存,它们是CPU运算过程中非常重要的部分。程序的位数(32位或64位)决定了程序在内存中如何存储和处理数据,以及它如何与CPU的寄存器交互。

在32位程序中:

  • 数据寄存器(如EAX, EBX, ECX, EDX在x86架构中)通常是32位宽的。
  • 地址寄存器(如EIP,表示指令指针)也是32位宽,这限制了程序能够直接访问的内存地址范围。
  • 其他类型的寄存器(如浮点寄存器、状态寄存器等)也可能有相应的32位版本或与32位数据操作相兼容。

在64位程序中:

  • 数据寄存器(如RAX, RBX, RCX, RDX在x86-64架构中)扩展到64位宽。
  • 地址寄存器(如RIP,表示指令指针)也是64位宽,允许程序访问更大的内存地址空间。
  • 同样,其他类型的寄存器也扩展到64位或提供了与64位数据操作相兼容的版本。

此外,64位系统通常具有更大的寄存器集合,这意味着CPU可以在不进行内存访问的情况下存储更多的中间计算结果,从而提高性能。

因此,当我们说一个程序是32位或64位时,我们不仅指的是它在内存中的表示方式,还指的是它与CPU寄存器的交互方式以及它能够处理的数据量。这也解释了为什么64位程序通常能够在处理大量数据和进行复杂计算时比32位程序表现得更好。

posted on   del88  阅读(394)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
历史上的今天:
2016-04-30 Delphi字符串、PChar与字符数组之间的转换
2016-04-30 查看当前操作系统的编码
2016-04-30 String、ANSIString、PChar及TBytes之间的转换 BytesOf move stringof
2016-04-30 原创 gif png bmp jeg 显示方法
点击右上角即可分享
微信分享提示