ConcurrentDictionary的AddOrUpdate方法抛出IndexOutOfRangeException

作业被不同的线程添加到HashSet中,并引发此错误。有什么解决办法吗?

ConcurrentDictionary<myKey,HashSet<Job>> _dictKeyJob;

_dictKeyJob.AddOrupdate(myKey,key =>
{
    return new HashSet<Job>({ Job };
},(key,hashJobs) =>
{
    if (Job.Status == eStatus.Cancelled)
    {
        hashJobs.Remove(Job);
    }
    else
    {
        hashJobs.Add(Job);
    }
    return hashJobs;
});

例外:

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at System.Collections.Generic.HashSet`1.SetCapacity(Int32 newSize,Boolean forceNewHashCodes)
   at System.Collections.Generic.HashSet`1.AddIfNotPresent(T value)
   at Raj.OPS.Common.Test.<>c__DisplayClass38_0.<SetOrAddKey>b__1(mKey key,HashSet`1 hashJobs) in 
   at System.Collections.Concurrent.ConcurrentDictionary`2.**AddOrupdate**(TKey key,Func`2 addValueFactory,Func`3 updateValueFactory)
shiqing22 回答:ConcurrentDictionary的AddOrUpdate方法抛出IndexOutOfRangeException

摘自ConcurrentDictionary.AddOrUpdate方法的文档:

  

对于字典的修改和写操作,ConcurrentDictionary<TKey,TValue>使用细粒度的锁定来确保线程安全。 (对字典的读取操作以无锁的方式执行。)但是,addValueFactoryupdateValueFactory的委托被称为在锁之外,以避免可能出现的问题。在锁下执行未知代码。因此,对于AddOrUpdate类上的所有其他操作,ConcurrentDictionary<TKey,TValue>并不是原子的。

(添加了重点)

因此,您不能使用HashSet作为ConcurrentDictionary的值,而不能在没有保护的情况下从多个线程更新它。它将损坏,并开始引发随机异常,如您观察到的异常。您应该使用锁来保护它(为每个HashSet使用不同的锁定对象以减少争用),或者使用concurrent HashSet(没有ConcurrentHashSet类,因此必须使用嵌套的) ConcurrentDictionary

关于第一个选项,即涉及lock的选项,您应该在访问同一HashSet的所有位置使用相同的锁定对象,而不仅是在内部 AddOrUpdate方法的回调。

尽管有可能通过使用工作流方法(TPL Dataflow库支持的方法)消除所有增加应用程序开销的同步。否则可能无法实现。这取决于您正在做的事情。

本文链接:https://www.f2er.com/3135084.html

大家都在问