我遇到了多个线程正在创建一个ICollection对象的情况。ConcurrentBag似乎是最好的(?)解决方案,因为-1)每个线程将拥有自己的本地队列,并且2)线程不需要进行通信-它们是独立的。到目前为止,一切都很好,但事实是我需要从该方法返回一个ISet(在所有生产者都终止之后)。即使当前的ConcurrentBag实例是不同的(由于应用程序的逻辑得到保证),我仍然需要将其转换为ISet,例如HashSet。至此,不再有生产者。现在是真正的问题:
迭代ConcurrentBag时,调用线程是否将为不在线程本地队列中的每个项目获取锁?还是每个线程会抓住一次锁?另外,仅迭代bag和调用bag.Distinct()显式地,锁定方式之间的内部实现是否有所不同?
看一下以下源代码ConcurrentBag
:http : //referencesource.microsoft.com/#System/sys/system/collections/concurrent/ConcurrentBag.cs,537a65e966c1c38d
遍历袋子触发对的呼叫FreezeBag
。此方法调用AcquireAllLocks
,浏览每个线程的队列并设置一个锁:
/// <summary>
/// local helper method to acquire all local lists locks
/// </summary>
private void AcquireAllLocks()
{
Contract.Assert(Monitor.IsEntered(GlobalListsLock));
bool lockTaken = false;
ThreadLocalList currentList = m_headList;
while (currentList != null)
{
// Try/Finally bllock to avoid thread aport between acquiring the lock and setting the taken flag
try
{
Monitor.Enter(currentList, ref lockTaken);
}
finally
{
if (lockTaken)
{
currentList.m_lockTaken = true;
lockTaken = false;
}
}
currentList = currentList.m_nextList;
}
}
每个线程将获取一次锁,而不是每个项目一次。
迭代或Distinct
两者都调用将调用该GetEnumerator
方法,因此不会有什么区别。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句