Pag*_*Sun 44 c# multithreading dictionary locking
当页面初始化将从配置文件加载一些信息时,我们的网站有一个配置页面,如"config.aspx".为了缓存加载的信息,我们提供了一个工厂类,我们调用工厂的公共方法来获取页面加载时的配置实例.但有时当重新启动应用程序池时,我们在事件日志中发现了一些错误消息,如下所示:
Message: Object reference not set to an instance of an object. Stack: at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value) at ObjectFactory.GetInstance(string key) at config.Page_Load(Object sender, EventArgs e) at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) at System.Web.UI.Control.OnLoad(EventArgs e) at System.Web.UI.Control.LoadRecursive() at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
工厂类实现如下:
public static class ObjectFactory
{
private static object _InternalSyncObject;
private static Dictionary _Instances;
private static object InternalSyncObject
{
get
{
if (_InternalSyncObject == null)
{
var @object = new object();
Interlocked.CompareExchange(ref _InternalSyncObject, @object, null);
}
return _InternalSyncObject;
}
}
private static Dictionary Instances
{
get
{
if (_Instances == null)
{
lock (InternalSyncObject)
{
if (_Instances == null)
{
_Instances = new Dictionary();
}
}
}
return _Instances;
}
}
private static object LoadInstance(string key)
{
object obj = null;
// some statements to load an specific instance from a configuration file.
return obj;
}
public static object GetInstance(string key)
{
object instance;
if (false == Instances.TryGetValue(key, out instance))
{
instance = LoadInstance(key);
Instances[key] = instance;
}
return instance;
}
}
我猜这个异常是由"Instances [key] = instance;"行抛出的,因为它是唯一可以调用set_Item
字典方法的代码.但是如果"Instances"值为null,则NullReferenceException
在调用TryGetValue
方法时会抛出一个,而堆栈跟踪的顶部框架应该GetInstance
不是Insert
.有没有人知道字典在多线程场景中如何NullReferenceException
调用set_Item
方法?
Guf*_*ffa 52
由于异常发生在Dictionary
代码内部,这意味着您同时Dictionary
从多个线程访问同一个实例.
您需要同步GetInstance
方法中的代码,以便一次只能访问一个线程Dictionary
.
编辑:
单独锁定访问,以便在执行(假设)耗时的加载时不在锁内:
private static object _sync = new object();
public static object GetInstance(string key) {
object instance = null;
bool found;
lock (_sync) {
found = Instances.TryGetValue(key, out instance);
}
if (!found) {
instance = LoadInstance(key);
lock (_sync) {
object current;
if (Instances.TryGetValue(key, out current)) {
// some other thread already loaded the object, so we use that instead
instance = current;
} else {
Instances[key] = instance;
}
}
}
return instance;
}
Run Code Online (Sandbox Code Playgroud)
引用http://msdn.microsoft.com/en-us/library/xfhwa508.aspx(由我添加的重点):
" 线程安全
此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的.任何实例成员都不保证是线程安全的.
A Dictionary<(Of <(TKey, TValue>)>)
可以同时支持多个读取器,只要不修改集合即可.即便如此,通过集合枚举本质上不是一个线程安全的过程.在枚举与写访问争用的极少数情况下,必须在整个枚举期间锁定该集合.为了允许多个线程访问集合进行读写,您必须实现自己的同步."
归档时间: |
|
查看次数: |
14712 次 |
最近记录: |