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

i3a*_*non 51 .net c# concurrency datetime tearing

在C#设置中,只要变量的大小最大native int(即32位运行时环境中的4个字节和64位上的8个字节),变量的值就是原子级.在一个64位的环境,它包括所有的引用类型和最内置值类型(byte,short,int,long,等等).

设置更大的值不是原子的,并且可能导致仅更新部分内存的撕裂.

DateTime是一个结构,它只包含一个ulong包含其所有数据(TicksDateTimeKind)的字段,并且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();
}
Run Code Online (Sandbox Code Playgroud)

Sco*_*ain 32

来自ECMA规范部分"I.12.6.6原子读写"

符合要求的CLI应保证native int当对位置的所有写访问都相同时,对正确对齐的内存位置的读写访问权限不大于本机字大小(类型的大小)是原子的(参见§I.12.6.2)尺寸.原子写入除了写入之外不得改变任何位.除非使用显式布局控制(请参阅分区II(控制实例布局))来更改默认行为,否则不应大于自然字大小(a的大小native int)的数据元素.对象引用应被视为存储在本机字大小中.

A native intIntPtrC#中的一个.

只要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
}
Run Code Online (Sandbox Code Playgroud)

  • @ i3arnon [这里是我运行的确切代码](https://gist.github.com/leftler/e45e6f68a0986408fad468080e7492f4),你只需要在项目构建设置中将程序集标记为不安全,但是我确实更新了我的示例函数at最后使用不安全的代码而不是编组类,因为你确实对潜在的大小差异做了一个很好的观点. (3认同)

Luc*_*ira 8

运行一些测试并基于上面的答案,可以说它今天是原子的.

我编写了一个测试来验证在N个线程的X迭代期间可以找到多少眼泪,用于Int64,DateTime和3个128,192和256尺寸的自定义结构 - 没有任何一个结构搞乱搞乱.

测试包括:

  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 --------------------
Run Code Online (Sandbox Code Playgroud)

测试代码可以在这里找到:https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e