DateTime 可以在 64 位环境中撕裂吗?
Can DateTime tear in a 64 bit environment?
在 C# 中,只要变量的大小最大为 native int
(即在 32 位运行时环境中为 4 个字节,在 64 位运行时环境中为 8 个字节),为变量设置值是原子的。
在包括所有引用类型和大多数内置值类型(byte
、short
、int
、long
等)的 64 位环境中。
设置更大的值不是原子的,可能会导致只有部分内存被更新的撕裂。
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();
}
来自 ECMA specification 部分 "I.12.6.6 Atomic reads and writes"
A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size (the size of type native int
) is atomic (see §I.12.6.2) when all the write accesses to a location are the same size. Atomic writes shall alter no bits other than those written. Unless explicit layout control (see Partition II (Controlling Instance Layout)) is used to alter the default behavior, data elements no larger than the natural word size (the size of a native int
) shall be properly aligned. Object references shall be treated as though they are stored in the native word size.
A native int
在 C# 中是 IntPtr
。
只要 sizeof(IntPtr) >= sizeof(DateTime)
对于运行时环境(又名:运行 为 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
}
来自 C# 语言规范。
5.5 Atomicity of variable references Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint,
int, float, and reference types. In addition, reads and writes of enum
types with an underlying type in the previous list are also atomic.
Reads and writes of other types, including long, ulong, double, and
decimal, as well as user-defined types, are not guaranteed to be
atomic. Aside from the library functions designed for that purpose,
there is no guarantee of atomic read-modify-write, such as in the case
of increment or decrement.
运行 一些测试和基于 今天可以很安全地说它是原子的。
我编写了一个测试来验证在 Int64、DateTime 和 3 个大小为 128、192 和 256 的自定义结构的 N 个线程上的 X 次迭代期间可以找到多少撕裂 - none 它们的 StructLayout 搞砸了。
测试包括:
- 将一组值添加到数组中以便它们是已知的。
- 为每个数组位置设置一个线程,该线程将数组中的值赋给一个共享变量。
- 设置相同数量的线程(array.length)从这个共享变量读取到本地。
- 检查这个局部是否包含在原始数组中。
在我的机器上(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 --------------------
测试代码可以在这里找到:https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e
在 C# 中,只要变量的大小最大为 native int
(即在 32 位运行时环境中为 4 个字节,在 64 位运行时环境中为 8 个字节),为变量设置值是原子的。
在包括所有引用类型和大多数内置值类型(byte
、short
、int
、long
等)的 64 位环境中。
设置更大的值不是原子的,可能会导致只有部分内存被更新的撕裂。
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();
}
来自 ECMA specification 部分 "I.12.6.6 Atomic reads and writes"
A conforming CLI shall guarantee that read and write access to properly aligned memory locations no larger than the native word size (the size of type
native int
) is atomic (see §I.12.6.2) when all the write accesses to a location are the same size. Atomic writes shall alter no bits other than those written. Unless explicit layout control (see Partition II (Controlling Instance Layout)) is used to alter the default behavior, data elements no larger than the natural word size (the size of anative int
) shall be properly aligned. Object references shall be treated as though they are stored in the native word size.
A native int
在 C# 中是 IntPtr
。
只要 sizeof(IntPtr) >= sizeof(DateTime)
对于运行时环境(又名:运行 为 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
}
来自 C# 语言规范。
5.5 Atomicity of variable references Reads and writes of the following data types are atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types. In addition, reads and writes of enum types with an underlying type in the previous list are also atomic. Reads and writes of other types, including long, ulong, double, and decimal, as well as user-defined types, are not guaranteed to be atomic. Aside from the library functions designed for that purpose, there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.
运行 一些测试和基于
我编写了一个测试来验证在 Int64、DateTime 和 3 个大小为 128、192 和 256 的自定义结构的 N 个线程上的 X 次迭代期间可以找到多少撕裂 - none 它们的 StructLayout 搞砸了。
测试包括:
- 将一组值添加到数组中以便它们是已知的。
- 为每个数组位置设置一个线程,该线程将数组中的值赋给一个共享变量。
- 设置相同数量的线程(array.length)从这个共享变量读取到本地。
- 检查这个局部是否包含在原始数组中。
在我的机器上(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 --------------------
测试代码可以在这里找到:https://gist.github.com/Flash3001/da5bd3ca800f674082dd8030ef70cf4e