繁体   English   中英

C#值类型参数复制线程安全

[英]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是混合之间12345

对于大于32位的类型的任何基本操作在x86机器上都不是原子操作,与64位和x64相同。

这并不意味着你可以对int使用任何操作都是安全的,例如:

从多核处理器操作一个int++someInt两个线程中的++someInt ,即使它编译成inc x86指令,也会发生以下情况。

  • someInt是9。
  • 核心1从其缓存中获取someInt
  • core 2从缓存中获取someInt
  • core 1将其值增加到10并将其保存到缓存中。
  • core 2将其值增加到10并将其保存到缓存中。

someInt增加了两倍,但它等于10。

例如,使用Interlocked将编译为lock inc ,这将锁定总线并确保核心拥有相关缓存的独占所有权。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM