[英]Updating reference to a member variable in use
我得到了这个单例缓存对象,它公开了一个 IEnumerable 属性,该属性只返回一个私有的 IEnumerable 变量。
我的单例对象上有一个静态方法,用于更新此成员变量(存在于此缓存对象的单个“实例”实例中)。
假设我的缓存正在更新时,某个线程当前正在迭代这个 IEnumerable 变量/属性。 我这样做是为了让缓存在一个新的局部变量上更新,最后将公开的私有变量设置为指向这个新的局部变量。
我知道我只是在更新一个引用,将另一个(旧)对象留在内存中等待 GC 获取,但我的问题是 - 我不是 100% 确定一旦我设置了新引用会发生什么? 另一个线程会突然迭代新对象还是通过 IEnumerable 接口传递的旧对象? 如果它是一个正常的参考,我会说“不”。 调用线程将在旧对象上运行,但我不确定 IEnumerable 是否也是这种情况?
这是精简的课程:
internal sealed class SektionCache : CacheBase
{
public static readonly SektionCache Instance = new SektionCache();
private static readonly object lockObject = new object();
private static bool isUpdating;
private IEnumerable<Sektion> sektioner;
static SektionCache()
{
UpdateCache();
}
public IEnumerable<Sektion> Sektioner
{
get { return sektioner; }
}
public static void UpdateCache()
{
// SNIP - getting data, locking etc.
Instance.sektioner = newSektioner;
// SNIP
}
}
由于 getter { return sektioner; }
{ return sektioner; }
在将新值放入字段之前调用,返回旧值。 然后, foreach (Sektion s in cache.Sektioner)
循环foreach (Sektion s in cache.Sektioner)
使用调用 getter 时收到的值,即旧值。 该值将在整个 foreach 循环中使用。
即使您更新单例中的引用,当前正在枚举 sektioner 的线程也将继续枚举它。 实现 IEnumerable 的对象没有什么特别之处。
您也许应该将volatile关键字添加到 sektioner 字段,因为您没有提供读锁定并且多个线程正在读/写它。
首先我看不到对象锁定,未使用的 lockObject 变量让我很伤心。 IEnumerable 并不特殊。 每个线程都有自己的对 sektioner 对象实例的引用副本。 您不能以这种方式影响其他线程。 sektioner 字段指向的旧版本数据会发生什么在很大程度上取决于主叫方。
我认为,如果你想要线程安全,你应该使用这种方式:
internal sealed class SektionCache : CacheBase
{
//public static readonly SektionCache Instance = new SektionCache();
// this template is better ( safer ) than the previous one, for thread-safe singleton patter >>>
private static SektionCache defaultInstance;
private static object readonly lockObject = new object();
public static SektionCach Default {
get {
SektionCach result = defaultInstance;
if ( null == result ) {
lock( lockObject ) {
if ( null == result ) {
defaultInstance = result = new SektionCache();
}
}
}
return result;
}
}
// <<< this template is better ( safer ) than the previous one
//private static readonly object lockObject = new object();
//private static bool isUpdating;
//private IEnumerable<Sektion> sektioner;
// this declaration is enough
private volatile IEnumerable<Sektion> sektioner;
// no static constructor is required >>>
//static SektionCache()
//{
// UpdateCache();
//}
// <<< no static constructor is required
// I think, you can use getter and setter for reading & changing a collection
public IEnumerable<Sektion> Sektioner {
get {
IEnumerable<Sektion> result = this.sektioner;
// i don't know, if you need this functionality >>>
// if ( null == result ) { result = new Sektion[0]; }
// <<< i don't know, if you need this functionality
return result;
}
set { this.sektion = value; }
}
//public static void UpdateCache()
//{
//// SNIP - getting data, locking etc.
//Instance.sektioner = newSektioner;
//// SNIP
//}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.