I outsourced my terrain generation into threads. The threads don’t use any unity api stuff and all variables which the thread and the main thread have access to are thread safed via a lock.
My problem is that after a few seconds (sometime 3-4s and sometimes 30s or 40s) the unity editor freezes.
If I open up the task manager the cpu and memory percentages are still changing (cpu is about 40-50% and memory about 300mb).
I’ve already tried unmanged threads and managed thread with the C# ThreadPool. The communication with the main thread goes over a status variable (which is locked) so if the task has finished the main thread collects the data and creates a mesh (every update the main thread checks for the status of the thread).
I’ve tried it on windows 10 with Unity 5.3/5.4 and on mac os x with unity 5.3/5.4.
Here’s the shortened code:
Edit: Updated code, now using volatile
public enum SurfaceCalculationStatus{
NewJob,
Processing,
DataReady,
Ready,
Aborted
}
public class SurfaceCalculation {
private SurfaceRenderType srt;
//Some members...
private volatile SurfaceCalculationStatus scs;
public SurfaceCalculation(){
scs = SurfaceCalculationStatus.Ready;
ThreadPool.QueueUserWorkItem((o) => { ThreadFunction();});
}
public void Init(int x, int z, int size, int gridSize, SurfaceRenderType srt, Chunk c){
//Some inits...
scs = SurfaceCalculationStatus.NewJob;
}
private void ThreadFunction()
{
while (true) {
if(scs == SurfaceCalculationStatus.Aborted)
{
return;
}
if (scs == SurfaceCalculationStatus.NewJob) {
scs = SurfaceCalculationStatus.Processing;
//Heavy calculations
scs = SurfaceCalculationStatus.DataReady;
}
Thread.Sleep (100);
}
}
public void AbortThread(){
scs = SurfaceCalculationStatus.Aborted;
}
//Some Getter & Setters...
public void SetReady(){
scs = SurfaceCalculationStatus.Ready;
}
public bool IsReady(){
return scs == SurfaceCalculationStatus.Ready;
}
public bool IsData(){
return scs == SurfaceCalculationStatus.DataReady;
}
}
Edit: This is the class/logic which manages the threads. If I comment out the line
sc.SetReady ();
at the Update() method there is no freezing.
public class SurfaceFactory {
private static List<Chunk>[] waitingQueue;
private static SurfaceCalculation[] inProgressQueue;
public static void Init(){
waitingQueue = new List<Chunk>[WorldSettings.lvlRadii.Length];
inProgressQueue = new SurfaceCalculation[SystemInfo.processorCount * 8];
for (int i = 0; i < inProgressQueue.Length; i++) {
inProgressQueue *= new SurfaceCalculation ();*
-
}*
-
for (int i = 0; i < waitingQueue.Length; i++) {*
_ waitingQueue = new List ();_
* }*
* }*
* public static void CreateSurface(Chunk c){*
* if (GetFreeThreadCound() > 0) {*
* StartSurfaceCalculation (c);*
* } else {*
* waitingQueue[c.GetLOD()].Add (c);*
* }*
* }*
* public static void Update(){*
* for (int i = inProgressQueue.Length - 1; i >= 0; i–) {*
_ SurfaceCalculation sc = inProgressQueue ;
* if (sc.IsData ()) {
//Thread finished*
/Chunk c = sc.GetChunk();
Mesh mesh = new Mesh ();
mesh.vertices = sc.GetVertices ();
mesh.triangles = sc.GetIndices ();
mesh.RecalculateNormals ();
c.SetMesh (mesh);/
* sc.SetReady ();
}
}*_
* int numberOfWaitingChunks = 0;*
* for (int i = 0; i < waitingQueue.Length; i++) {*
_ numberOfWaitingChunks += waitingQueue .Count;
* }*_
* int numberFreeThreads = GetFreeThreadCound ();*
* while (numberOfWaitingChunks > 0 && numberFreeThreads > 0){*
* for (int i = 0; i < waitingQueue.Length; i++) {*
_ if (waitingQueue .Count > 0) {
Chunk c = waitingQueue [0];
waitingQueue*.RemoveAt (0);
StartSurfaceCalculation (c);
numberFreeThreads–;
}
}
}
}*_
* public static void AbortThreads(){*
* for (int i = 0; i < inProgressQueue.Length; i++) {*
_ inProgressQueue .AbortThread ();
* }
}*_
* private static void StartSurfaceCalculation(Chunk c){*
* SurfaceCalculation sc = GetFreeThread ();*
* if (sc != null) {*
* sc.Init (c.GetChunkXMeters (false), c.GetChunkZMeters (false), c.GetSize (), c.GetGridSize (), c.GetSurfaceRenderType (), c);*
* } else {*
* waitingQueue [c.GetLOD ()].Add (c);*
* }*
* }*
* private static int GetFreeThreadCound(){*
* int c = 0;*
* for (int i = 0; i < inProgressQueue.Length; i++) {*
_ if (inProgressQueue .IsReady ())
* c++;
}
return c;
}*_
* private static SurfaceCalculation GetFreeThread(){*
* for (int i = 0; i < inProgressQueue.Length; i++) {*
_ if (inProgressQueue .IsReady ())
return inProgressQueue ;
* }
return null;
}
}*_