C# 中的线程、值类型和引用类型说明?

Posted

技术标签:

【中文标题】C# 中的线程、值类型和引用类型说明?【英文标题】:Threading in C# , value types and reference types clarification? 【发布时间】:2012-11-20 19:22:03 【问题描述】:

在阅读了来自 msdn 的 Jon Skeet article 和 this 文章后,我还有一个问题

假设我有这个代码:

  MyPerson mp = new MyPerson(); //Field

  int g=0; //Field

  public void DoWork ()
   
      int i;
      MyPerson mp2 = new MyPerson();  
      ...
   

现在假设我有 2 个线程。运行DoWork。 (让我们暂时忽略竞争条件)

他们会看到相同的g 还是每个线程都有自己的项目? ? (价值)

他们会看到相同的mp 还是每个线程都有自己的项目?? (实例)

他们会看到相同的i 还是每个线程都有自己的项目? (价值)

他们会看到相同的mp2 还是每个线程都有自己的项目? (实例)

如果他们看到的相同,我为什么需要static

我已经搜索了很多关于这个主题的内容,找不到找到 任何文章,其中指出:不同的线程、引用类型和值类型.. .)

【问题讨论】:

调用线程代码如何创建类? @asawyer 只在 main 中运行了 3 次 ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork ),null); @RoyiNamir 在上面一行中,目标实例每次都是this - 实际上是new WaitCallback(this.DoWork)。因此,如果您的代码执行 3 次,则可以:它们是针对同一实例的 3 个委托,因此 mpg 是共享的请注意我所说的不一定会观察到更改除非您使用内存屏障(同步)或volatile 访问。由于非常复杂的原因。 @MarcGravell 但writing 不需要内存屏障/锁定/易失性。正确的 ?只读...? @RoyiNamir 取决于很多因素;例如,虽然是:所有写入都实现为 volatile 写入,但这是一个不应该使用的实现细节(在执行线程语义时,您关心的是保证,并且:is' t)。此外,它取决于数据大小:intfloat 等,加上引用保证是原子写入;但是大型结构(包括doublelong保证是原子写入。对于原语,Interlocked 很方便;但除此之外:您肯定需要同步以避免损坏值。 【参考方案1】:

两个线程都没有简单地“运行DoWork”;他们在特定对象上运行DoWork 。如果两个线程是针对不同的实例创建的,那么mpg 将是完全独立的字段。如果两个线程是针对相同实例创建的,那么mpg 将被共享但是不能保证线程会看到由除非您使用同步或volatile 访问,否则其他线程。

例如:

var obj = new SomeObject();
Thread thread1 = new Thread(obj.DoWork);
Thread thread2 = new Thread(obj.DoWork); // clearly targeting the same instance

var obj = new SomeObject();
Thread thread1 = new Thread(obj.DoWork);
obj = new SomeObject();
Thread thread2 = new Thread(obj.DoWork); // targeting a different instance

局部变量imp2 严格针对每个线程。

补充说明:即使它们是单独的字段/本地,如果 ... 中的某些代码稍后重新分配 mpmp2 以引用同一对象,那么它们会为同一个对象争吵;将应用相同的同步/volatile 规则。

【讨论】:

Marc,你能否解释一下如果两个线程是针对不同的实例创建的 基本上,实际上它在内部是如何工作的,是将对象的实例作为“this”传递给DoWork方法。我认为这是一种很好的可视化方式。 (实际上,一个类上的所有实例方法都有一个第一个参数是“this”) @MarcGravell 如果有另一种称为 DoWork2() 的方法会创建 2 个运行 DoWork() 的线程。是不是和针对同一个实例解释一样?【参考方案2】:

变量gmp 对包含类来说是“全局的”,因此它们将是两个线程看到的相同对象。 i 是在DoWork 事件中声明的局部变量;随后,这将仅对背景/替代线程“可见”。

他们不“看到”相同的东西,因此在这种情况下,static 关键字没有相关性。

我希望这会有所帮助。

【讨论】:

'global' 具有误导性,它们处于类级别。 同意。马克在这里的回答是优越的。我已经进行了编辑......虽然这个答案没问题:/ Marc 的回答并不优秀,他是优秀的。 @RoyiNamir 并不优秀 - 只是因为每一个错误都犯了十几次而伤痕累累,并向其中一些人学习

以上是关于C# 中的线程、值类型和引用类型说明?的主要内容,如果未能解决你的问题,请参考以下文章

值类型和引用类型原理

C# 值类型和引用类型

C# 引用类型和值类型

c#中的引用类型和值类型有啥区别?

C#详解值类型和引用类型区别

C#中的引用传递值传递