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

ret*_*ent 7 c# collections multithreading

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

Mic*_*urr 8

您希望锁定使用SyncRoot哪个是同步方法Hashtable将锁定的对象:

lock (sessionsTimeoutData.SyncRoot)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

请参阅http://msdn.microsoft.com/en-us/library/system.collections.hashtable.synchronized.aspx:

枚举通过集合本质上不是线程安全的过程.即使集合是同步的,其他线程仍然可以修改集合,这会导致枚举器抛出异常.为了在枚举期间保证线程安全,您可以在整个枚举期间锁定集合,也可以捕获由其他线程所做的更改导致的异常.

以下代码示例演示如何在整个枚举期间使用SyncRoot锁定集合:

Hashtable myCollection = new Hashtable();
lock(myCollection.SyncRoot)
{
    foreach (object item in myCollection)
    {
        // Insert your code here.
    }
}
Run Code Online (Sandbox Code Playgroud)