c# - 解决集合的并发问题

标签 c# .net collections concurrency thread-safety

我在与正在开发的多人同步游戏同时使用共享集合时遇到问题。我进行了一些挖掘,并在 Alexey Drobyshevsky 关于 codeproject 的帖子中找到了一个简洁的线程安全 IEnumerator/IList 实现:

http://www.codeproject.com/KB/cs/safe_enumerable.aspx

在采用他的实现后,我什至用 for/foreach 循环替换了共享集合上的所有 Linq 查询,因为 Linq 查询仍在使用底层的不安全 IEnumerable。

这是我对 SafeList 的实现,列表本身作为 ReadOnlyCollection 暴露给使用类。

http://theburningmonk.com/2010/03/thread-safe-enumeration-in-csharp/

切换到此 SafeList 后,我​​看到的问题少得多,但在重负载下(80 多个线程,所有线程都在不同的点从列表读取/写入)我仍然看到 InvalidOperationException 被抛出:

The element list has changed. The enumeration operation failed to continue

我什至尝试在 SafeList 的实现中使用 ReadWriterLockSlim 代替锁定对象,但结果也没有结果。到目前为止,我唯一的其他建议是每次线程需要循环时克隆列表。我希望避免每次都克隆该列表,因为该列表在太多地方使用,这可能会影响性能并可能引入其他难以发现的错误。

考虑到时间限制,我必须务实一点,如果克隆是解决这个问题最安全、最快捷的方法,那么我可以接受,但在诉诸最后的尝试之前,我'我只是想知道是否有人遇到过类似的事情能够提供一些建议。

非常感谢!

[编辑] 以下是我按要求看到的问题的更多信息:

对于一个“游戏”,最多可以有 100 个左右的同步客户端连接,游戏需要每隔几秒向每个连接的客户端发送更新消息,因此每隔几秒这个游戏需要迭代玩家的共享列表. 当玩家加入或离开时,列表需要相应地更新以反射(reflect)变化。 除此之外,玩家可以与游戏互动并与其他玩家聊天,每次收到玩家的消息时,游戏都需要再次遍历同一个列表并进行广播。 当游戏尝试向玩家广播消息(读取操作),同时许多玩家同时离开/加入(写入操作)时,通常会抛出异常。

最佳答案

根据您对游戏结构的描述,考虑使用一个线程作为唯一可以直接访问玩家列表的线程。使列表对那个线程有效私有(private)。

任何其他线程访问列表的方式是向列表管理器线程发送消息。因此该线程有一个等待的消息队列。当队列非空时,它会按照消息的指示咀嚼消息。他们可能会说“添加新玩家”或“移除玩家”或“将此玩家的状态更新为‘不开心’”。

该线程还可以定期扫描列表以将更新发送给客户端,或者它可以(甚至更好)利用它具有列表正在发生的已知更改流这一事实,并将这些更改转发到客户。

基本原则:将数据私有(private)化为一个线程,线程之间通过消息队列进行通信。

您的基本数据结构是一个线程安全的队列类。 SO 上已经有许多示例。 (并避开任何声称“无锁”但线程安全的东西。不值得冒这个风险。)

关于c# - 解决集合的并发问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2383446/

相关文章:

c# - 单击 ASHX 图片下载

c# - 使用 XmlDocument 保留 xml 格式

c# - 从 gridview 插入数据时处理 'NULL' 和键约束

.net - C3374 : can't take address of 'function' unless creating delegate instance

java - 类型不匹配 : cannot convert from List<String> to ArrayList<String>

javascript - 解析 ASP.Net 通过 cookie 发送的 JavaScript 中的日期

c# - 当前上下文中不存在名称 'WM_DEVICECHANGE'

c# - Eazfuscator.NET 破坏了 Enum.IsDefined

java - java.util.Collections.sort() 方法的时间复杂度是多少?

java - 在 mongodb 集合中找到一些值?