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 个委托,因此 mp
和 g
是共享的但请注意我所说的不一定会观察到更改除非您使用内存屏障(同步)或volatile
访问。由于非常复杂的原因。
@MarcGravell 但writing
不需要内存屏障/锁定/易失性。正确的 ?只读...?
@RoyiNamir 取决于很多因素;例如,虽然是:所有写入都实现为 volatile 写入,但这是一个不应该使用的实现细节(在执行线程语义时,您关心的是保证,并且:is' t)。此外,它取决于数据大小:int
、float
等,加上引用保证是原子写入;但是大型结构(包括double
和long
)不保证是原子写入。对于原语,Interlocked
很方便;但除此之外:您肯定需要同步以避免损坏值。
【参考方案1】:
两个线程都没有简单地“运行DoWork
”;他们在特定对象上运行DoWork
。如果两个线程是针对不同的实例创建的,那么mp
和g
将是完全独立的字段。如果两个线程是针对相同实例创建的,那么mp
和g
将被共享但是不能保证线程会看到由除非您使用同步或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
局部变量i
和mp2
严格针对每个线程。
补充说明:即使它们是单独的字段/本地,如果 ...
中的某些代码稍后重新分配 mp
或 mp2
以引用同一对象,那么它们会为同一个对象争吵;将应用相同的同步/volatile
规则。
【讨论】:
Marc,你能否解释一下如果两个线程是针对不同的实例创建的? 基本上,实际上它在内部是如何工作的,是将对象的实例作为“this
”传递给DoWork
方法。我认为这是一种很好的可视化方式。 (实际上,一个类上的所有实例方法都有一个第一个参数是“this
”)
@MarcGravell 如果有另一种称为 DoWork2()
的方法会创建 2 个运行 DoWork()
的线程。是不是和针对同一个实例解释一样?【参考方案2】:
变量g
和mp
对包含类来说是“全局的”,因此它们将是两个线程看到的相同对象。 i
是在DoWork
事件中声明的局部变量;随后,这将仅对背景/替代线程“可见”。
他们不“看到”相同的东西,因此在这种情况下,static
关键字没有相关性。
我希望这会有所帮助。
【讨论】:
'global' 具有误导性,它们处于类级别。 同意。马克在这里的回答是优越的。我已经进行了编辑......虽然这个答案没问题:/ Marc 的回答并不优秀,他是优秀的。 @RoyiNamir 并不优秀 - 只是因为每一个错误都犯了十几次而伤痕累累,并向其中一些人学习以上是关于C# 中的线程、值类型和引用类型说明?的主要内容,如果未能解决你的问题,请参考以下文章