Может ли DateTime разрываться в 64-битной среде?


в C# установка значения переменной является атомарной до тех пор, пока ее размер не превышает native int (т. е. 4 байта в 32-разрядной среде выполнения и 8 байт в 64-разрядной). В 64-разрядной среде, включающей все типы ссылок и большинство встроенных типов значений (byte,short,int,long и т. д.).

установка большего значения не является атомарной и может вызвать разрыв, когда обновляется только часть памяти.

DateTime - это структура, которая включает в себя только один ulong поле, содержащее все свои данные (Ticks и DateTimeKind) и 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();
}
3 51

3 ответа:

С спецификация ECMA раздел "I. 12. 6. 6 Atomic читает и пишет"

соответствующий CLI гарантирует, что доступ для чтения и записи к правильно выровненным ячейкам памяти не превышает размер собственного слова (размер типа native int) является атомарным (см. §I. 12.6.2), когда все записи доступа к местоположению имеют одинаковый размер. Атомарные записи не должны изменять никаких битов, кроме записанных. Если только явное управление макетом (см. Раздел II (управление Макет экземпляра)) используется для изменения поведения по умолчанию, элементы данных не больше, чем естественный размер слова (размер native int) должны быть правильно выровнены. Ссылки на объекты должны рассматриваться так, как если бы они хранились в собственном размере слова.

A native int это IntPtr в C#.

пока sizeof(IntPtr) >= sizeof(DateTime) верно для среды выполнения (aka: работает как 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
}

запуск некоторых тестов и на основе ответ выше Это довольно безопасно сказать, что это сегодня атомных.

Я написал тест, чтобы проверить, сколько разрывов можно найти во время X итераций над N потоками для Int64, DateTime и 3 пользовательских структур 128, 192 и 256 размеров - ни один из них не испортил StructLayout.

тест состоит из:

  1. добавление набора значений в массив, чтобы они были известны.
  2. настройка одного потока для каждой позиции массива этот поток присвоит значение из массива общей переменной.
  3. настройка такого же количества потоков (массив.length)для чтения из этой общей переменной в локальную.
  4. проверьте, если этот локальный содержится в исходном массиве.

результаты следующие в моей машине (Core i7-4500U, Windows 10 x64, .NET 4.6, выпуск без отладки, платформа target: 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

из спецификации языка C#.

5.5 атомарность ссылок на переменные чтение и запись следующих типов данных являются атомарными:bool, char, byte, sbyte, short, ushort, uint, int, float и ссылочные типы. Кроме того, читает и пишет перечисления типы с базовым типом в предыдущем списке также являются атомарными. Читает и пишет других типов, в том числе длинный, улун, двойной, и десятичные, а также пользовательские типы, не являются гарантировано будет атомный. Помимо библиотечных функций, предназначенных для этой цели, нет никакой гарантии атомарного чтения-изменения-записи, как в случае приращения или убывания.