C# 同步由两个不同线程访问的两个列表

问题描述 投票:0回答:1

我有一个游戏中的对象列表,这些对象可能每秒运行多次复杂的碰撞测试,也可能不运行。

因为这种碰撞测试非常昂贵,所以每个对象都有一个预先计算的潜在碰撞候选者的列表。在每个模拟步骤开始时,该列表都会被清除并重新填充。当 A 和 B 的球形碰撞盒(围绕实际碰撞盒)相交时,对象 A 是对象 B 的潜在候选者。

潜在碰撞候选列表的预计算当前是在同一线程上完成的,但我想将其移至不同的线程。 对于少量对象,这已经可以正常工作,但是我创建的对象越多,每个对象的候选列表就越经常以某种方式始终为空。

这就是两个线程正在做的事情:

主题#1:

  • 循环遍历所有对象并调用它们的 Update() 方法。
    • 在此更新方法中,每个对象都运行 GetIntersections(),它循环遍历潜在碰撞候选者列表并执行真正的碰撞检测

主题#2:

  • 扫描和修剪算法循环遍历所有对象并且:
    • 清除他们的候选人名单
    • 填充对象的候选列表

线程 #1 每秒比线程 #2 运行得更频繁(这是预期的行为)。

只要其中一个线程对任何候选列表具有写访问权限,我就会使用 lock(...){ } 。但不知何故,我添加到场景中的对象越多,每个对象的候选列表就越频繁地为空。这会导致许多对象不再与任何对象发生碰撞,因为它们的候选列表通常是空的,而它们中应该至少有一个对象。

如何正确同步?

c# list multithreading collections thread-safety
1个回答
0
投票

System.Collections.Generic命名空间中的集合类 包括列表和字典。这些课程提供 与之前相比,改进了类型安全性和性能 System.Collections 类。然而,System.Collections.Generic 类不提供任何线程同步;用户代码必须 在添加或删除项目时提供所有同步 多个线程并发。

我们建议使用并发集合类 System.Collections.Concurrent 命名空间,因为它们提供类型 安全性以及更高效和完整的线程安全性。

List<T>
不是线程安全的,看看 线程安全集合

System.Collections.Concurrent 命名空间包括几个 线程安全且可扩展的集合类。多种的 线程可以安全有效地添加或删除这些项目 集合,无需用户额外同步 代码。当您编写新代码时,请使用并发集合类 同时将多个线程写入集合。如果你是 仅从共享集合中读取,然后您可以使用其中的类 System.Collections.Generic 命名空间。

您可以在被认为是线程安全的System.Collections.Concurrent下使用ConcurrentBag Class

© www.soinside.com 2019 - 2024. All rights reserved.