Подтвердить что ты не робот

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

В параметре С# значение переменной равно атомному, если его размер не превышает 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();
}
4b9b3361

Ответ 1

Из спецификация ECMA раздел "I.12.6.6 Атомные чтения и записи"

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

A native int является IntPtr в С#.

Пока sizeof(IntPtr) >= sizeof(DateTime) истинно для среды выполнения (aka: running as 64 bit), и они не изменяют внутреннюю структуру, чтобы быть явным макетом с несогласованными байтами вместо [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
}

Ответ 2

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

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

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

  • Добавление набора значений в массив, чтобы они были известны.
  • Настройка одного потока для каждой позиции массива, этот поток присваивает значение из массива общей переменной.
  • Настройка того же количества потоков (array.length) для чтения из этой общей переменной в локальную.
  • Проверьте, содержится ли этот локал в исходном массиве.

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

Ответ 3

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

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