Skip to main content
 首页 » 编程设计

c#之阻止并发集合,例如 ConcurrentBag 或 BlockingCollection

2024年01月24日23lovecherry

我想执行两个访问 ConcurrentBag 的语句,中间没有任何其他线程访问它。例如:

ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>(); 
concurrentBag.Add(1); 
int check = 0; 
//Somehow block so that the following two statements will  
//be executed without any other thread accessing concurrentBag. 
concurrentBag.TryPeek(out check); 
if (check == 2) concurrentBag.Add(3); 

如何做到这一点?

请您参考如下方法:

我怀疑这比用 lock 关键字包装几行代码要困难得多。原因是您必须用锁包装对 ConcurrentBag 的所有 访问。如果你这样做了,那么它就不再是“并发的”了。我认为您要求的是一种暂时暂停集合的并发行为以支持序列化行为的方法,然后在完成特殊的 protected 操作后再次恢复其并发行为。

天真的方法是创建您自己的集合,通过在内部将其用作基础集合来提供与 ConcurrentBag 相同的操作。然后,您将提供 SuspendConcurrent 和 ResumeConcurrent 操作,通过设置和重置标志(可能通过 Interlocked.CompareExchange)切换集合的并发行为方法)。然后代码将使用此标志来确定是直接将 Add、TryPeek 和 TryTake 操作转发到基础集合还是使用硬锁在这样做之前。我认为最终您会发现代码非常复杂并且难以正确。根据个人经验,您现在设想的任何微不足道的实现都可能是错误的、低效的,或者在您希望的时候无法完全并发。

我的建议是找出一种方法来重构您的代码,以便消除此要求。

编辑:

从您的一条评论看来,您似乎想要一个 CAS like能够根据某事是否已经发生来做出决定的操作。有多种选择,但可能最适合您需要的一种是使用提供 TryAdd 方法的 ConcurrentDictionary 类。 TryAdd 如果键不存在则返回 true。如果 key 确实存在,那么它将返回 false。许多线程可以使用同一个键同时执行此方法,但只有一个线程会得到真正的响应。然后,您可以使用 if 语句根据返回值控制程序流。