- Home /
Multithreading, Waiting for threads to complete.
I am trying to create a script what keeps a pool of 8 threads. I am trying to set up a management class to handle these and when a thread finishes, it needs to notify the management class so that it can pass the data in a threadsafe way. I am having trouble with the synchronization though, it seems to thread fine for a while but then all of a sudden the thread queue just empties itself and it only ends up doing around 38 threads out of 184 in the queue. Here are the scripts what I am using so far :
Thread Manager :
using System;
using System.Collections.Generic;
using UnityEngine;
public class RenderThreadManager
{
public static RenderThread[] activeThreads;
public static int threadCount = 8;
public static int activeThreadCount = 0;
public static List<object[]> threadQueue = new List<object[]>();
public static bool initialized = false;
public static RenderThreadObject threadObject;
public static int count = 0;
public static void onFinished()
{
count++;
}
public static void queueThread(object[] data)
{
check();
threadQueue.Add(data);
}
public static void startThread(int index, object data)
{
activeThreads[index].threadAlive = true;
activeThreads[index].startThread();
getActiveThreads();
}
public static void stopThread(int index)
{
activeThreads[index].threadAlive = false;
getActiveThreads();
}
static void check()
{
if (!initialized)
{
activeThreads = new RenderThread[threadCount];
for (int i = 0; i < threadCount; i++)
{
activeThreads[i] = new RenderThread();
activeThreads[i].id = i;
}
threadObject = new GameObject().AddComponent<RenderThreadObject>();
threadObject.name = "Thread Object";
initialized = true;
}
}
public static int getActiveThreads()
{
activeThreadCount = 0;
for(int i = 0; i < activeThreads.Length; i++)
{
if(activeThreads[i].threadAlive)
{
activeThreadCount++;
}
}
return activeThreadCount;
}
// Called every frame from thread object.
public static void threadLoop()
{
getActiveThreads();
for (int i = 0; i < activeThreads.Length; i++)
{
if (activeThreads[i].getState() == true)
{
activeThreads[i].onFinished();
//stopThread(i);
}
}
for(int i = 0; i < threadQueue.Count; i++)
{
if(getActiveThreads() < threadCount)
{
startThread(activeThreadCount, threadQueue[i]);
threadQueue.RemoveAt(i);
}
}
}
}
Thread Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Text;
using UnityEngine;
public class RenderThread
{
public int id; // ID Value in array of threads.
public bool completedTask = false; // Has the thread finished its task?
public bool cancelled = false; // Has the thread been cancelled?
public bool threadAlive = false; // Is the thread in use?
public object taskLock = new object(); // Lock object for locking task boolean
private BackgroundWorker workerThread; // Thread instance.
public void startThread()
{
workerThread = new BackgroundWorker();
workerThread.DoWork += new DoWorkEventHandler(workerThread_work);
workerThread.ProgressChanged += new ProgressChangedEventHandler(workerThread_Progress);
workerThread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerThread_Complete);
workerThread.WorkerReportsProgress = true;
workerThread.WorkerSupportsCancellation = true;
Logger.Log("Starting thread with ID " + id);
workerThread.RunWorkerAsync();
}
public void cancelThread()
{
workerThread.CancelAsync();
}
public void onFinished()
{
threadAlive = false;
completedTask = false;
cancelled = false;
RenderThreadManager.onFinished();
Logger.Log("Finished thread with ID " + id);
}
private void workerThread_Complete(object sender, RunWorkerCompletedEventArgs e)
{
setState(true);
}
private void workerThread_Progress(object sender, ProgressChangedEventArgs e)
{
}
private void workerThread_work(object sender, DoWorkEventArgs e)
{
for(int i = 0; i < 100; i++)
{
Thread.Sleep(10);
if(checkForCancel(sender,e))
{
e.Cancel = true;
workerThread.ReportProgress(0);
break;
}
}
workerThread.ReportProgress(100);
}
private bool checkForCancel(object sender, DoWorkEventArgs e)
{
if(workerThread.CancellationPending)
{
return true;
}
return false;
}
public bool getState()
{
lock (taskLock)
{
return completedTask;
}
}
public void setState(bool state)
{
lock (taskLock)
{
completedTask = state;
}
}
}
It would be really helpful if someone could notify me on what I am doing wrong or possible alternatives to this system.
Thanks,
Looks like you've got an interesting manager there that you may well need the functions of - I could suggest you look at my Loom class which works using a call back to the main thread method that could be implemented alongside some kind of Promises framework for the completion part.
Don't have time to review your code now - but I'll come back and have a look to see if I can spot what's up.
I was actually looking at you're class earlier, I saw it looked quite useful, the only reason why I did not go with that was because I wanted to try my own attempt at it before I start to look into using someone else's work. I will be sure to take another look at how you're doing it though because I will surely learn a lot from it.
Does anybody have any information on some alternate method of doing a thread queue? Even a basic example would be really helpful!
So I guess with your code I don't "like" the way that the thread active status is counted - it "feels" like that could get out of sync. It would probably be better to use a try/finally to ensure the thread count was incremented and decremented together
Your answer
Follow this Question
Related Questions
Weird Threading Issue 0 Answers
Unity Backgroundworker threading 2 Answers
[C#] How to use a Multi Threaded Job Queue for Math function 2 Answers
"...can only be called from the main thread" - MultiThreading 1 Answer
How does unity thread works? 0 Answers