InvalidOperationException:Collection已被修改 - 尽管锁定了集合

时间:2011-04-23 05:53:03

标签: c# multithreading collections

我有一个同步哈希表,我定期删除一些条目。多个线程运行此代码。所以我锁定了整个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); }

3 个答案:

答案 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);

进入锁定的部分。