[英]C# value type parameter copy thread safety
假设我有一个struct
:
struct Foo{}
已经在堆上分配(作为class
成员),并且我有许多线程可以读取和写入该struct
。 如果我将变量传递给某个函数:
void Bar(Foo param);
param将是该struct
的副本。 复制操作本身是否安全?
复制操作对于任何大于int
东西都不是线程安全的(它一次被提取,因此没有任何东西可以干扰它的值)。
如果你接受大于4个字节的任何东西,那么该值可能会被4×4字节取出,而在这些操作之间,另一个线程可能会改变部分值。
例如,加载long
不是线程安全的,因为在32位机器上,另一个线程可以将其写入,然后您将读取一半旧值和另一半新值。
所有这些代表结构,如果它们占用超过4个字节。
永远不要假设任何操作默认是线程安全的 - 因为它不是。
例如,考虑以下Types
:
public class A
{
public B b;
}
public struct B
{
public int a;
public int b;
public int c;
public int d;
}
以及以下方法:
public static void Func(B b)
{
Console.WriteLine($"{b.a}, {b.b}, {b.c}, {b.d}");
}
如果您将使用以下Main
方法并暂停控制台一次:
A a = new A();
new Thread(() =>
{
while (true)
{
a.b.a = 5;
a.b.b = 5;
a.b.c = 5;
a.b.d = 5;
}
}).Start();
while (true)
{
a.b.a = 1;
a.b.b = 2;
a.b.c = 3;
a.b.d = 4;
Func(a.b);
}
你会看到一些的structs
是混合之间1
, 2
, 3
, 4
和5
。
对于大于32位的类型的任何基本操作在x86
机器上都不是原子操作,与64位和x64
相同。
这并不意味着你可以对int
使用任何操作都是安全的,例如:
从多核处理器操作一个int
, ++someInt
两个线程中的++someInt
,即使它编译成inc
x86
指令,也会发生以下情况。
someInt
是9。 someInt
。 someInt
。 someInt
增加了两倍,但它等于10。
例如,使用Interlocked
将编译为lock inc
,这将锁定总线并确保核心拥有相关缓存的独占所有权。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.