我刚刚遇到了这个问题 - 是否可以在C#中跨线程安全地访问对象。
E.g。用代码
//Somewhere long ago
MyClass myVar = new MyClass("First Instance");
//Then later, happening at the same time
//In thread one
myVar = new MyClass("Second Instance");
//In thread two
myVar.PrintName();
我不关心是使用第一个还是第二个实例,但myVar有可能在某些时候根本无效(例如指向不存在的位置,因为对象引用可能只是部分更新在用于其他线程之前)
关于锁的问题:
如果我保留锁定 - 那么所有未完成的写入都会被提交给内存吗?
我的问题是,如果我在锁中引用变量,我知道只有一个线程可以同时访问锁 - 但是我可以在一个线程中写入变量(而且只能写到了缓存),然后在另一个线程中甚至在锁内部获取变量的旧值(因为缓存未提交或者我仍然在该线程的缓存中有旧值)?
答案 0 :(得分:1)
到你的第一个。它几乎肯定是安全的,但我会锁定它。
关于你的缓存问题你在谈论什么缓存,我能想到的唯一一个就是CPU缓存,如果我们担心这些是否脏,需要刷新我们都会在很多麻烦。
修改强> 从您的评论我看到CPU缓存就是您所指的。
Mutli-core和多处理器硬件可确保不会使用过时的缓存中的任何数据。
答案 1 :(得分:1)
我知道你的问题是关于.NET的,我不能告诉你那里的答案。但是,在Java中,这段代码绝对不安全。
风险在于代码重新排序(优化步骤)会在构造函数完成运行之前看到对象引用被更新 - 因此第二个线程可以看到第二个对象的部分构造版本。
在java中,你可以通过使对象引用volatile,或者在某种AtomicReference(或当然通过同步)后面保护它来解决这个问题 - 任何一个都强加了一个“内存障碍”,限制了可以进行的优化完成以确保部分构造的对象永远不可见。
正如我所说,我对.NET内存模型知之甚少,不知道.NET是否会出现同样的问题。
答案 2 :(得分:0)
您问题中的代码示例是线程安全的。显然取决于你在构造函数中做了什么,但“通常”myVar ref将是有效的(一般来说,你可以做一些低级别的事情,比如FormatterServices等)。将使用构造函数创建一个新对象,并将自动返回到正确的线程。对我来说,这是通过在每个线程上创建新对象来确保代码是线程安全的最佳方法之一。
答案 3 :(得分:0)
我想说,只要你没有明确地解除引用对象,就没有存在空引用的威胁。唯一的时间可能是在初始化myVar之前启动第二个线程。在这个简单的例子中,我认为你不需要锁定。至于你的问题,你指的是哪个缓存?