web-dev-qa-db-fra.com

DateTime peut-il se déchirer dans un environnement 64 bits?

En C #, définir une valeur sur une variable est atomique tant que sa taille est au plus native int (c'est-à-dire 4 octets dans un environnement d'exécution 32 bits et 8 octets sur un environnement 64 bits). Dans un environnement 64 bits qui inclut tous les types de références et la plupart des types de valeurs intégrés (byte, short, int, long, etc.) .

La définition d'une valeur plus élevée n'est pas atomique et peut provoquer un déchirement là où seule une partie de la mémoire est mise à jour.

DateTime est une structure qui ne comprend qu'un seul champ ulong contenant toutes ses données (Ticks et le DateTimeKind) et ulong seul est atomique dans un environnement 64 bits.

Est-ce à dire que DateTime est également atomique? Ou le code suivant peut-il conduire à un déchirement à un moment donné?

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();
}
51
i3arnon

De la section spécification ECMA "I.12.6.6 Atomic lit et écrit"

Une CLI conforme garantira que l'accès en lecture et en écriture à des emplacements de mémoire correctement alignés ne dépassant pas la taille du mot natif (la taille du type native int) Est atomique (voir §I.12.6.2) lorsque tous les accès en écriture à un emplacement sont de la même taille. Les écritures atomiques ne doivent pas modifier d'autres bits que ceux écrits. À moins qu'un contrôle explicite de la disposition (voir Partition II (Contrôle de la disposition des instances)) soit utilisé pour modifier le comportement par défaut, les éléments de données ne dépassant pas la taille naturelle du mot (la taille d'un native int) Doivent être correctement alignés. Les références d'objets doivent être traitées comme si elles étaient stockées dans la taille native de Word.

Un native int Est un IntPtr en C #.

Tant que sizeof(IntPtr) >= sizeof(DateTime) est vrai pour l'environnement d'exécution (alias: fonctionnant en 64 bits), et qu'ils ne modifient pas la structure interne pour être une mise en page explicite avec des octets mal alignés au lieu de [StructLayout(LayoutKind.Auto)] il possède actuellement, puis lit et écrit une structure DateTime (ou toute autre structure qui suit ces règles) sont garanties atomiques par la spécification ECMA.

Vous pouvez le vérifier en exécutant le code suivant dans un environnement 64 bits:

public unsafe static void Main()
{
    Console.WriteLine(sizeof(DateTime)); // Outputs 8
    Console.WriteLine(sizeof(IntPtr)); // Outputs 8
    Console.WriteLine(sizeof(ulong)); // Outputs 8
}
32
Scott Chamberlain

Exécuter quelques tests et basé sur réponse ci-dessus il est assez sûr de dire qu'il est atomique aujourd'hui.

J'ai écrit un test pour vérifier combien de larmes ont pu être trouvées pendant les itérations X sur N threads pour Int64, DateTime et 3 structures personnalisées de 128, 192 et 256 tailles - aucune avec leur StructLayout foiré.

Le test consiste en:

  1. Ajout d'un ensemble de valeurs à un tableau afin qu'elles soient connues.
  2. En configurant un thread pour chaque position du tableau, ce thread attribuera la valeur du tableau à une variable partagée.
  3. Configuration du même nombre de threads (array.length) pour lire de cette variable partagée à un local.
  4. Vérifiez si ce local est contenu dans le tableau d'origine.

Les résultats sont les suivants sur ma machine (Core i7-4500U, Windows 10 x64, .NET 4.6, version sans débogage, cible de la plate-forme: x64 avec optimisation de code):

-------------- 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 --------------------

Le code du test peut être trouvé ici: https://Gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e

8
Lucas Teixeira

De la spécification du langage C #.

5.5 Atomicité des références de variables Les lectures et écritures des types de données suivants sont atomiques: bool, char, byte, sbyte, short, ushort, uint, int, float et reference types. De plus, les lectures et écritures des types enum avec un type sous-jacent dans la liste précédente sont également atomiques. Les lectures et écritures d'autres types, y compris long, ulong, double et décimal, ainsi que les types définis par l'utilisateur, ne sont pas garantis pour être atomique. Hormis les fonctions de bibliothèque conçues à cet effet, il n'y a aucune garantie de lecture-modification-écriture atomique, comme dans le cas de l'incrémentation ou de la décrémentation.

1
OmariO