CBT2.0 Make Hull and Level methods thread-safe using ThreadLocal

Replaced instance fields with ThreadLocal collections in Hull.GetConnectedHulls and Level.GetCells to ensure thread safety during parallel updates. Methods now return copies of the collections to prevent concurrent modification issues.
This commit is contained in:
Eero
2025-12-29 18:20:37 +08:00
parent 7b8275100d
commit 854d7bea1f
2 changed files with 19 additions and 4 deletions

View File

@@ -1214,15 +1214,22 @@ namespace Barotrauma
}
}
private readonly HashSet<Hull> adjacentHulls = new HashSet<Hull>();
/// <summary>
/// Used in <see cref="GetConnectedHulls"/> - ThreadLocal for thread safety during parallel updates
/// </summary>
private static readonly ThreadLocal<HashSet<Hull>> adjacentHullsLocal =
new ThreadLocal<HashSet<Hull>>(() => new HashSet<Hull>());
public IEnumerable<Hull> GetConnectedHulls(bool includingThis, int? searchDepth = null, bool ignoreClosedGaps = false)
{
var adjacentHulls = adjacentHullsLocal.Value;
adjacentHulls.Clear();
int startStep = 0;
searchDepth ??= 100;
GetAdjacentHulls(adjacentHulls, ref startStep, searchDepth.Value, ignoreClosedGaps);
if (!includingThis) { adjacentHulls.Remove(this); }
return adjacentHulls;
// Return a copy to prevent concurrent modification if the caller enumerates while another thread calls this method
return adjacentHulls.ToHashSet();
}
private void GetAdjacentHulls(HashSet<Hull> connectedHulls, ref int step, int searchDepth, bool ignoreClosedGaps = false)

View File

@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Voronoi2;
@@ -3655,9 +3656,15 @@ namespace Barotrauma
return cells;
}
private readonly List<VoronoiCell> tempCells = new List<VoronoiCell>();
/// <summary>
/// Used in <see cref="GetCells"/> - ThreadLocal for thread safety during parallel updates
/// </summary>
private static readonly ThreadLocal<List<VoronoiCell>> tempCellsLocal =
new ThreadLocal<List<VoronoiCell>>(() => new List<VoronoiCell>());
public List<VoronoiCell> GetCells(Vector2 worldPos, int searchDepth = 2)
{
var tempCells = tempCellsLocal.Value;
tempCells.Clear();
int gridPosX = (int)Math.Floor(worldPos.X / GridCellSize);
int gridPosY = (int)Math.Floor(worldPos.Y / GridCellSize);
@@ -3712,7 +3719,8 @@ namespace Barotrauma
tempCells.AddRange(abyssIsland.Cells);
}
return tempCells;
// Return a copy to prevent concurrent modification if the caller enumerates while another thread calls this method
return tempCells.ToList();
}
public VoronoiCell GetClosestCell(Vector2 worldPos)