可以在64位环境中撕毁DateTime吗?

在C#中,将变量的值设置为原子的,只要其大小最大为DateTime(即在32位运行时环境中为4个字节,在64位环境中为8个字节)。在包含所有引用类型和大多数内置值类型(ulongTicksDateTimeKindulong等)的64位环境中。

设置一个较大的值不是原子的,并且可能导致仅更新部分内存的情况发生中断。

DateTime是仅包含一个包含所有数据(TicksDateTimeKind)的单个ulong字段的结构,而ulong本身在64位环境中是原子的。

这是否也意味着DateTime是原子的? 还是下面的代码在某些时候会导致撕裂?

static DateTime _value;
static void Main()
{
    for (int i = 0; i < 10; i++)
    {
        new Thread(_ =>
        {
            var random = new Random();
            while (true)
            {
                _value = new DateTime((long)random.Next() << 30 | (long)random.Next());
            }
        }).Start();
    }

    Console.ReadLine();
}
i3arnon asked 2020-01-23T09:07:58Z
3个解决方案
32 votes

来自ECMA规范部分“ I.12.6.6原子读取和写入”

如果对某个位置的所有写访问均为原子访问(即§I.12.6.2),则合格的CLI必须保证对不大于本机字大小(sizeof(IntPtr) >= sizeof(DateTime)类型的大小)的正确对齐的内存位置的读写访问是原子的(请参见§I.12.6.2)。 一样的大小。 原子写入不得更改已写入的其他位。 除非使用显式布局控制(请参阅分区II(控制实例布局))来更改默认行为,否则数据元素的大小应不超过自然字长([StructLayout(LayoutKind.Auto)])。 对象引用应被视为以本机字长存储。

sizeof(IntPtr) >= sizeof(DateTime)是C#中的[StructLayout(LayoutKind.Auto)]

只要sizeof(IntPtr) >= sizeof(DateTime)对于运行时环境(也称为:以64位运行)为真,并且它们不会将内部结构更改为具有未对齐字节的显式布局,而不是其当前具有的[StructLayout(LayoutKind.Auto)],则可以读取和写入DateTime ECMA规范保证该结构(或遵循这些规则的任何其他结构)是原子的。

您可以通过在64位环境中运行以下代码来验证这一点:

public unsafe static void Main()
{
    Console.WriteLine(sizeof(DateTime)); // Outputs 8
    Console.WriteLine(sizeof(IntPtr)); // Outputs 8
    Console.WriteLine(sizeof(ulong)); // Outputs 8
}
Scott Chamberlain answered 2020-01-23T09:08:42Z
8 votes

运行一些测试并根据上述答案,可以肯定地说它是原子的。

我编写了一个测试,以验证在Int64,DateTime和3个128、192和256大小的自定义结构的N个线程的X迭代过程中,可以发现有多少泪水-没有一个StructLayout被弄乱了。

该测试包括:

  1. 向数组添加一组值,以便它们被知道。
  2. 为每个数组位置设置一个线程,该线程会将数组中的值分配给共享变量。
  3. 设置相同数量的线程(array.length)以从此共享变量读取到本地。
  4. 检查此本地数组是否包含在原始数组中。

我的机器中的结果如下(Core i7-4500U,Windows 10 x64,.NET 4.6,不带调试的发行版,平台目标:具有代码优化功能的x64):

-------------- Trying to Tear --------------
Running: 64bits
Max Threads: 30
Max Reruns: 10
Iterations per Thread: 20000
--------------------------------------------
----- Tears ------ | -------- Size ---------
          0             Int64 (64bits)
          0             DateTime (64bits)
         23             Struct128 (128bits)
         87             Struct192 (192bits)
         43             Struct256 (256bits)
----- Tears ------ | -------- Size ---------
          0             Int64 (64bits)
          0             DateTime (64bits)
         44             Struct128 (128bits)
         59             Struct192 (192bits)
         52             Struct256 (256bits)
----- Tears ------ | -------- Size ---------
          0             Int64 (64bits)
          0             DateTime (64bits)
         26             Struct128 (128bits)
         53             Struct192 (192bits)
         45             Struct256 (256bits)
----- Tears ------ | -------- Size ---------
          0             Int64 (64bits)
          0             DateTime (64bits)
         46             Struct128 (128bits)
         57             Struct192 (192bits)
         56             Struct256 (256bits)
------------------- End --------------------

可以在以下位置找到测试代码:[https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e]

Lucas Teixeira answered 2020-01-23T09:09:38Z
1 votes

来自C#语言规范。

5.5变量引用的原子性以下数据类型的读写是原子的:bool,char,byte,sbyte,short,ushort,uint,   int,float和引用类型。 另外,读写枚举   上一个列表中具有基础类型的类型也是原子的。   读取和写入其他类型,包括long,ulong,double和   十进制以及用户定义的类型不保证为   原子。 除了为此目的设计的库函数之外,   不能保证原子读取-修改-写入,例如   递增或递减。

OmariO answered 2020-01-23T09:10:04Z
translate from https://stackoverflow.com:/questions/42258346/can-datetime-tear-in-a-64-bit-environment