System.Collections.Generic.Dictionary<,>
只要不修改该集合,Dictionary 就可以同时支持多个阅读器。即便如此,从头到尾对一个集合进行枚举本质上并不是一个线程安全的过程。当出现枚举与写访问互相争用这种极少发生的情况时,必须在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步。今天解决了使用Dictionary泛型类的时候出现一个错误 “System.InvalidOpervationException "集合已经修改,可能无法执行枚举操作"”。原来的代码如下:
private
void
CheckingTimeout()
{
List < string > list = new List < string > ();
lock (sessions)
{
foreach ( string sessionKey in sessions.Keys)
{
if (sessions[sessionKey].IsTimeouted)
{
logger.Info( " 会话 [ " + sessionKey + " ] 超时 " );
UnLoadSession(sessionKey);
list.Add(sessionKey);
}
}
foreach ( string key in list)
{
sessions.Remove(key);
}
}
}
public void UnloadSession( string sessionID)
{
lock (sessions)
{
if (sessions.ContainsKey(sessionID))
{
db.Delete(GetSessionFromDatabase(sessionID));
dispatcher.UnregisterAllOutEventSubscriber(sessionID);
sessions.Remove(sessionID);
}
}
}
{
List < string > list = new List < string > ();
lock (sessions)
{
foreach ( string sessionKey in sessions.Keys)
{
if (sessions[sessionKey].IsTimeouted)
{
logger.Info( " 会话 [ " + sessionKey + " ] 超时 " );
UnLoadSession(sessionKey);
list.Add(sessionKey);
}
}
foreach ( string key in list)
{
sessions.Remove(key);
}
}
}
public void UnloadSession( string sessionID)
{
lock (sessions)
{
if (sessions.ContainsKey(sessionID))
{
db.Delete(GetSessionFromDatabase(sessionID));
dispatcher.UnregisterAllOutEventSubscriber(sessionID);
sessions.Remove(sessionID);
}
}
}
错误出现的原因是代码中在枚举的过程中修改了集合,而造成了这个错误,修改后的代码如下:
private
void
CheckingTimeout()
{
List < string > list = new List < string > ();
lock (sessions)
{
foreach ( string sessionKey in sessions.Keys)
{
if (sessions[sessionKey].IsTimeouted)
{
logger.Info( " 会话 [ " + sessionKey + " ] 超时 " );
UnregisterSession(sessionKey);
list.Add(sessionKey);
}
}
foreach ( string key in list)
{
sessions.Remove(key);
}
}
}
private void UnregisterSession( string sessionID)
{
lock (sessions)
{
if (sessions.ContainsKey(sessionID))
{
db.Delete(GetSessionFromDatabase(sessionID));
dispatcher.UnregisterAllOutEventSubscriber(sessionID);
}
}
}
{
List < string > list = new List < string > ();
lock (sessions)
{
foreach ( string sessionKey in sessions.Keys)
{
if (sessions[sessionKey].IsTimeouted)
{
logger.Info( " 会话 [ " + sessionKey + " ] 超时 " );
UnregisterSession(sessionKey);
list.Add(sessionKey);
}
}
foreach ( string key in list)
{
sessions.Remove(key);
}
}
}
private void UnregisterSession( string sessionID)
{
lock (sessions)
{
if (sessions.ContainsKey(sessionID))
{
db.Delete(GetSessionFromDatabase(sessionID));
dispatcher.UnregisterAllOutEventSubscriber(sessionID);
}
}
}