我正在使用自己的多线程来处理我的算法独立路径寻找统一。但是,当我执行两个相同的类时,我得到内存泄漏,当只执行一个实例时,我有没有问题。如果有必要,我真的想要至少使用两个线程。
以下是我遇到的课程。请记住,两个独立的线程必须执行此脚本的一部分。 AddJob
可以从主统一线程调用,但最有可能从代理的另一个更新线程调用。
namespace Plugins.PathFinding.Threading
{
internal class PathFindingThread
{
private Thread m_Worker;
private volatile Queue<CompletedProcessingCallback> m_CallbackQueue;
private volatile Queue<IAlgorithm> m_QueuedTasks;
internal int GetTaskCount
{
get
{
return m_QueuedTasks.Count;
}
}
internal PathFindingThread()
{
m_Worker = new Thread(Run);
m_CallbackQueue = new Queue<CompletedProcessingCallback>();
m_QueuedTasks = new Queue<IAlgorithm>();
}
private void Run()
{
Debug.Log("<b><color=green> [ThreadInfo]:</color></b> PathFinding Thread Started ");
try
{
while(true)
{
if (m_QueuedTasks.Count > 0)
{
IAlgorithm RunningTask = m_QueuedTasks.Dequeue();
RunningTask.FindPath(new IAlgorithmCompleted(AddCallback));
}
else
break;
}
Debug.Log("<b><color=red> [ThreadInfo]:</color></b> PathFinding Worker is idle and has been Stopped");
}
catch(Exception)
{
Debug.Log("<b><color=red> [ThreadInfo]:</color></b> PathFinding thread encountred an error and has been aborted");
}
}
internal void AddJob(IAlgorithm AlgorithmToRun)
{
m_QueuedTasks.Enqueue(AlgorithmToRun);
//Debug.Log("Added Job To Queue");
}
private void AddCallback(CompletedProcessingCallback callback)
{
m_CallbackQueue.Enqueue(callback);
}
private void Update()
{
if (m_CallbackQueue.Count > 0)
{
if (m_CallbackQueue.Peek().m_Callback != null) { }
m_CallbackQueue.Peek().m_Callback.Invoke(m_CallbackQueue.Peek().m_Path);
m_CallbackQueue.Dequeue();
}
if (m_Worker.ThreadState != ThreadState.Running && m_QueuedTasks.Count != 0)
{
m_Worker = new Thread(Run);
m_Worker.Start();
}
}
}
internal delegate void IAlgorithmCompleted(CompletedProcessingCallback callback);
internal struct CompletedProcessingCallback
{
internal volatile FindPathCompleteCallback m_Callback;
internal volatile List<GridNode> m_Path;
}
}
namespace Plugins.PathFinding
{
internal enum TypeOfNode
{
Ground,
Air
}
//used to store location information since array can only take rounded numbers
internal struct Position
{
internal int x;
internal int y;
internal int z;
}
internal class GridNode
{
internal Position M_PostitionInGrid { get; private set; }
internal Vector3 M_PostitionInWorld { get; private set; }
internal TypeOfNode M_type { get; private set; }
internal bool m_IsWalkable = true;
internal GridNode m_ParrentNode;
internal int Hcost;
internal int Gcost;
internal int Fcost { get { return Hcost + Gcost; } }
internal GridNode(Position postion , Vector3 WorldPosition)
{
M_PostitionInGrid = postion;
m_IsWalkable = true;
M_PostitionInWorld = WorldPosition;
}
}
}
internal delegate void FindPathCompleteCallback(List<GridNode> Path);
internal abstract class IAlgorithm
{
protected GridNode m_SavedStart;
protected GridNode m_SavedTarget;
protected List<GridNode> m_LocatedPath;
protected FindPathCompleteCallback m_Callback;
internal FindPathCompleteCallback GetCallback
{
get
{
return m_Callback;
}
}
protected PathFindingGrid m_grid;
internal abstract void FindPath(IAlgorithmCompleted callback);
protected abstract List<GridNode> CreatePath(PathFindingGrid Grid, GridNode Start, GridNode Target);
protected abstract List<GridNode> RetracePath(GridNode start, GridNode target);
}
namespace Plugins.PathFinding.Astar
{
internal class AstarFinder : IAlgorithm
{
//construction of the Algorithm
internal AstarFinder(GridNode start, GridNode target, FindPathCompleteCallback Callback)
{
m_SavedStart = start;
m_SavedTarget = target;
m_Callback = Callback;
m_LocatedPath = new List<GridNode>();
m_grid = PathFindingGrid.GetInstance;
}
//function to start finding a path
internal override void FindPath(IAlgorithmCompleted callback)
{
//running Algorithm and getting the path
m_LocatedPath = CreatePath(PathFindingGrid.GetInstance, m_SavedStart, m_SavedTarget);
callback.Invoke(
new CompletedProcessingCallback()
{
m_Callback = m_Callback,
m_Path = m_LocatedPath
});
}
//Algorithm
protected override List<GridNode> CreatePath(PathFindingGrid Grid, GridNode Start, GridNode Target)
{
if(Grid == null ||
Start == null ||
Target == null)
{
UnityEngine.Debug.Log("Missing Parameter, might be outside of grid");
return new List<GridNode>();
}
List<GridNode> Path = new List<GridNode>();
List<GridNode> OpenSet = new List<GridNode>();
List<GridNode> ClosedSet = new List<GridNode>();
OpenSet.Add(Start);
int Retry = 0;
while (OpenSet.Count > 0)
{
if(Retry > 3000 || Grid == null)
{
UnityEngine.Debug.Log("Path Inpossible Exiting");
break;
}
GridNode CurrentNode = OpenSet[0];
for (int i = 0; i < OpenSet.Count; i++)
{
if(OpenSet[i].Fcost < CurrentNode.Fcost || OpenSet[i].Fcost == CurrentNode.Fcost && OpenSet[i].Hcost < CurrentNode.Hcost)
{
CurrentNode = OpenSet[i];
}
}
OpenSet.Remove(CurrentNode);
ClosedSet.Add(CurrentNode);
if(CurrentNode == Target)
{
Path = RetracePath(CurrentNode,Start);
break;
}
GridNode[] neighbour = Grid.GetNeighbouringNodes(CurrentNode);
for (int i = 0; i < neighbour.Length; i++)
{
if (!neighbour[i].m_IsWalkable || ClosedSet.Contains(neighbour[i]))
continue;
int CostToNeighbour = CurrentNode.Gcost + Grid.GetDistance(CurrentNode, neighbour[i]);
if(CostToNeighbour < neighbour[i].Gcost || !OpenSet.Contains(neighbour[i]))
{
neighbour[i].Gcost = CostToNeighbour;
neighbour[i].Hcost = Grid.GetDistance(neighbour[i], Target);
neighbour[i].m_ParrentNode = CurrentNode;
if (!OpenSet.Contains(neighbour[i]))
OpenSet.Add(neighbour[i]);
}
}
Retry++;
}
return Path;
}
//retracing the path out of a node map
protected override List<GridNode> RetracePath(GridNode start, GridNode target)
{
List<GridNode> Output = new List<GridNode>();
GridNode current = start;
while(current != target)
{
Output.Add(current);
current = current.m_ParrentNode;
}
Output.Reverse();
return Output;
}
}
}
答案 0 :(得分:0)
这表明代码的核心是线程安全的。
internal class PathFindingThread
{
Task m_Worker;
ConcurrentQueue<CompletedProcessingCallback> m_CallbackQueue;
ConcurrentQueue<IAlgorithm> m_QueuedTasks;
internal int GetTaskCount
{
get
{
return m_QueuedTasks.Count;
}
}
internal PathFindingThread()
{
m_CallbackQueue = new ConcurrentQueue<CompletedProcessingCallback>();
m_QueuedTasks = new ConcurrentQueue<IAlgorithm>();
m_Worker = Task.Factory.StartNew(() =>
{
while (true)
{
IAlgorithm head = null;
if (m_QueuedTasks.TryDequeue(out head))
{
head.FindPath(new IAlgorithmCompleted(AddCallback));
}
else
{
Task.Delay(0);
}
}
});
}
internal void AddJob(IAlgorithm AlgorithmToRun)
{
m_QueuedTasks.Enqueue(AlgorithmToRun);
}
private void AddCallback(CompletedProcessingCallback callback)
{
m_CallbackQueue.Enqueue(callback);
}
private void Update()
{
CompletedProcessingCallback cb = null;
if (m_CallbackQueue.TryDequeue(out cb))
{
cb.m_Callback.Invoke(cb.m_Path);
}
}
}
Volatile仅适用于更改字段的值 - 不调用字段引用的集合上的方法。
你可能不需要在CompletedProcessingCallback中使用Volatile,但它取决于使用它的其他地方。当然在结构域上具有易失性是一种难闻的气味。
首先解决这些线程问题,然后查看是否还有问题。