51 votes

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

En C#, l'attribution d'une valeur à une variable est atomique tant que sa taille est au maximum native int (c'est-à-dire 4 octets dans un environnement d'exécution 32 bits et 8 octets dans un environnement 64 bits). Dans un environnement 64 bits qui comprend 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 grande n'est pas atomique et peut provoquer des déchirures lorsque seule une partie de la mémoire est mise à jour.

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

Est-ce que cela signifie 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();
}

32voto

Scott Chamberlain Points 32782

De la Spécification de l'ECMA section "I.12.6.6 Lecture et écriture atomiques".

Un CLI conforme doit garantir que l'accès en lecture et en écriture à des emplacements mémoire correctement alignés ne dépassant pas la taille de mot native (la taille du type native int ) est atomique (voir §I.12.6.2) lorsque tous les accès en écriture à un emplacement ont la même taille. Les écritures atomiques ne modifient aucun autre bit que ceux qui sont écrits. À moins qu'un contrôle explicite de l'agencement (voir la Partition II (Contrôle de l'agencement des instances)) ne soit utilisé pour modifier le comportement par défaut, les éléments de données ne dépassant pas la taille naturelle d'un mot (la taille d'un fichier 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 de mot native.

A native int est un IntPtr en C#.

Tant que sizeof(IntPtr) >= sizeof(DateTime) est vrai pour l'environnement d'exécution (aka : exécution en 64 bit), et ils ne modifient pas la structure interne pour être une disposition explicite avec des octets mal alignés à la place de l'élément [StructLayout(LayoutKind.Auto)] qu'il possède actuellement, puis les lectures et les écritures d'une DateTime (ou toute autre structure qui suit ces règles) sont garanties comme étant 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
}

8voto

Lucas Teixeira Points 580

J'ai effectué quelques tests et, sur la base de l 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 déchirures pouvaient être trouvées pendant X itérations sur N threads pour Int64, DateTime et 3 structs personnalisés de 128, 192 et 256 tailles - aucun avec leur StructLayout foiré.

Le test consiste en :

  1. Ajout d'un ensemble de valeurs à un tableau pour qu'elles soient connues.
  2. La mise en place d'un thread pour chaque position du tableau, ce thread assignera la valeur du tableau à une variable partagée.
  3. Mise en place du même nombre de threads (array.length) pour lire depuis cette variable partagée vers un local.
  4. Vérifier 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, Release without debug, Platform target : x64 with code optimization) :

-------------- 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 pour le test peut être trouvé ici : https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e

1voto

OmariO Points 183

Extrait 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 types de référence . De plus, les lectures et écritures de types enum dont le type sous-jacent figure dans la liste précédente sont également atomiques. Les lectures et écritures d'autres types, y compris long, ulong, double, et décimaux, ainsi que les types définis par l'utilisateur, ne sont pas garantis. pour être atomique. En dehors des fonctions de bibliothèque conçues à cet effet, il n'y a aucune garantie de lecture-modification-écriture atomique, comme dans le cas où d'incrémentation ou de décrémentation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X