WeakReference<T> 的文档中有一个关于线程安全的通用套话:
任何此类型的公共静态成员(在 Visual Basic 中为共享成员)都是线程安全的。但任何实例成员不能保证是线程安全的。
但是,我想知道是否确实可以安全地使用 WeakReference<T> 的实例成员呢?
特别是,我想知道是否可以同时访问这样的内容是安全的:
任何此类型的公共静态成员(在 Visual Basic 中为共享成员)都是线程安全的。但任何实例成员不能保证是线程安全的。
但是,我想知道是否确实可以安全地使用 WeakReference<T> 的实例成员呢?
特别是,我想知道是否可以同时访问这样的内容是安全的:
class MyRef<T> where T : class
{
private readonly Func<Task<T>> _fetcher;
private readonly WeakReference<T> _wref;
public MyRef(Func<Task<T>> fetcher, T target = null)
{
_fetcher = fetcher;
_wref = new WeakReference<T>(target);
}
public async Task<T> GetTargetAsync()
{
T target;
if (!_wref.TryGetTarget(out target))
{
target = await _fetcher();
_wref.SetTarget(target);
}
return target;
}
}
这里同时使用了 TryGetTarget
和 SetTarget
,它们可能会被多个线程并发地调用。
它们都调用了由本地代码实现的私有外部 Target
属性。(参考源码)
在保护像上面那样的代码与同步锁之前,我想知道本地实现是否真的不安全以进行并发访问。
对我而言,什么是“安全”的?
简单来说,如果我可以使用上面的代码而不会因两种方法的并发调用导致任何意外异常或访问冲突,则为“安全”。
更明确地说:
TryGetTarget
要么返回一个非空引用的true
,要么返回false
。没有任何异常。SetTarget
不会引起任何异常。
WeakReference<T>
的文档底部写道:“此类型的任何公共静态成员(在 Visual Basic 中为 Shared)都是线程安全的。任何实例成员都不能保证是线程安全的。” (我强调) 因此,不能保证它不会崩溃。 - Lasse V. KarlsenSetTarget
在coreclr中的实现,它似乎受到AcquireWeakHandleSpinLock
保护,这是一种锁。因此它很可能是线程安全的。其中“很可能”更像是“今晚我很可能吃肉”而不是“明天太阳还会升起”的意思 :-) - xanatos