我有一个同步哈希表,我定期删除一些条目。多个线程运行此代码。所以我锁定了整个foreach,但我仍然有时会得到InvalidOperationException:Collection被修改了......在Hashtable.HashtableEnumerator.MoveNext() - 即在foreach循环中。 我究竟做错了什么?锁不够?
private static readonly Hashtable sessionsTimeoutData = Hashtable.Synchronized(new Hashtable(5000));
private static void ClearTimedoutSessions()
{
List keysToRemove = new List();
long now = DateTime.Now.Ticks;
lock (sessionsTimeoutData)
{
TimeoutData timeoutData;
foreach (DictionaryEntry entry in sessionsTimeoutData)
{
timeoutData = (TimeoutData)entry.Value;
if (now - timeoutData.LastAccessTime > timeoutData.UserTimeoutTicks)
keysToRemove.Add((ulong)entry.Key);
}
}
foreach (ulong key in keysToRemove)
sessionsTimeoutData.Remove(key);
}
答案 0 :(得分:8)
您希望使用SyncRoot
锁定,Hashtable
是同步lock (sessionsTimeoutData.SyncRoot)
{
// ...
}
的方法将锁定的对象:
Hashtable myCollection = new Hashtable();
lock(myCollection.SyncRoot)
{
foreach (object item in myCollection)
{
// Insert your code here.
}
}
请参阅http://msdn.microsoft.com/en-us/library/system.collections.hashtable.synchronized.aspx:
通过集合枚举是 本质上不是线程安全的 程序。即使是收藏品 同步,其他线程仍然可以 修改集合,这会导致 枚举器抛出异常。 确保螺纹安全 枚举,你可以锁定 整个收集 枚举或捕获异常 由其他人做出的改变 线程。
以下代码示例演示了如何操作 用这个来锁定集合 整个过程中的SyncRoot 枚举:
{{1}}
答案 1 :(得分:2)
为什么第二个foreach在锁外?
答案 2 :(得分:1)
您需要在移除时以及在计算要移除的内容时锁定。移动它,
foreach (ulong key in keysToRemove)
sessionsTimeoutData.Remove(key);
进入锁定的部分。