Can DateTime break in a 64-bit environment?

In the C # parameter, the value of the variable is atomic if its size does not exceed native int (i.e. 4 bytes in a 32-bit runtime environment and 8 bytes in a 64-bit environment). In a 64-bit environment, which includes all types of links and most of the built-in value types ( byte , short , int , long , etc.).

Setting a larger value is not atomic and may cause breaks when only part of the memory is updated.

DateTime is a structure that includes only one ulong field containing all its data ( Ticks and DateTimeKind ) and ulong itself is atomic in a 64-bit environment.

Does this mean that DateTime is atomic? Or can the following code cause a break at some point?

 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(); } 
+52
c # datetime concurrency tearing
Feb 15 '17 at 19:24
source share
3 answers

From the ECMA specification section "I.12.6.6 Atomic Reads and Writes"

The corresponding CLI should ensure that read and write access to correctly aligned memory cells does not exceed the size of the native word (size of type native int ) is atomic (see 1.1.6.2) when all write accesses to the location are the same size. Atomic records should not change any bits other than those written. If explicit layout control is not used to change the default behavior (see Section II (“Managing Instance Layouts”), data elements not exceeding the size of the natural word ( native int size) must be correctly aligned. Object references should be processed like this as if they were saved in the size of the native word.

A native int is IntPtr in C #.

So far, sizeof(IntPtr) >= sizeof(DateTime) true for the runtime (aka: running as 64 bit) and they do not change the internal structure to be an explicit layout with inconsistent bytes instead of [StructLayout(LayoutKind.Auto)] , which it has at present, then reading and writing a DateTime structure (or any other structure that follows these rules) is guaranteed to be atomic according to the ECMA specification.

You can verify that by executing the following code in a 64-bit environment:

 public unsafe static void Main() { Console.WriteLine(sizeof(DateTime)); // Outputs 8 Console.WriteLine(sizeof(IntPtr)); // Outputs 8 Console.WriteLine(sizeof(ulong)); // Outputs 8 } 
+32
Feb 15 '17 at 20:52
source share

Performing some tests and based on the answer above , it can be said that today it is atomic.

I wrote a test to check how many tears can be found during X-iterations over N threads for Int64, DateTime and 3 user structures of 128, 192 and 256 sizes - none of them are corrupted in StructLayout.

The test consists of:

  • Adding a set of values ​​to an array so that they are known.
  • Setting up one stream for each position of the array, this stream assigns a value from the array to a common variable.
  • Setting the same number of streams (array.length) to read from this shared variable to local.
  • Check if this locale is in the source array.

The results on my computer are as follows: Core i7-4500U, Windows 10 x64, .NET 4.6, Release without debugging, Platform: 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 -------------------- 

The code for the test can be found here: https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e

+8
Feb 17 '17 at 14:10
source share

From the C # language specification.

5.5 Atomicity of variable references Reading and writing of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float and reference . In addition, reading and writing enumeration types with a base type in the previous list are also atomic. Reads and writes other types, including long, ulong, double, and decimal, as well as custom types are not guaranteed . atomic. In addition to library functions designed for this purpose, there is no guarantee of atomic read-modify-write, for example, in the case of an increase or decrease.

-one
Feb 15 '17 at 20:54 on
source share



All Articles