Using BackgroundWorker with Unity, Completed not running on Main thread ?

I’m working on an app that communicates heavily with an API. In order to get the data from the API the app first has to parse the whole JSON it receives. I’m looking into moving the parsing part in a worker thread so it doesn’t create hiccups in the UI.

Now I know Unity’s API is not thread safe. But I’ve looked at the BackgroundWorker class which is supposed to run a work function on a separate worker thread and a completed function that should run on the same thread the worker was created on.

But it turns out the completed function won’t run on the main thread, it is actually running on the same worker thread which is definitely what I’m trying to avoid/bypass.

I’m testing this on a case where I have my ChallengesManager polling the server for a list of challenges, once received, I start the worked thread to parse and register the challenges in a Dictionnary>

 void OnChallengesLoaded(APIResponse r, Hashtable args){
		ResetChallengesList();
		Debug.Log("Current thread [Main] : " + System.Threading.Thread.CurrentThread.ManagedThreadId);

		InitWorker();

		JSONTask t = new JSONTask();
		t.toParse = r.body;

		bWorker.RunWorkerAsync(t);

		Debug.Log("Current thread [AfterStartBackground] : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

Then I have those two functions to do the work and for after it’s done :

void Worker_DoWork(object sender, DoWorkEventArgs e){
		Debug.Log("Starting work in background");
		JSONTask t = (JSONTask) e.Argument;
		Debug.Log("Current thread [Work] : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
		e.Result = t.Parse();
	}

	void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
		Debug.Log("Work done !");
		JSONNode node = (JSONNode) e.Result;
		if(node != null){
			RegisterChallenges(node, "toPlay");
			RegisterChallenges(node, "waitingForOpponent");
			RegisterChallenges(node, "finished");
			RegisterChallenges(node, "toBeReviewed");
		}
		Debug.Log("Challenges retrieved ! Waiting : " + challenges["waitingForOpponent"].Count + " Ready : " + challenges["toPlay"].Count + " Finished : " + challenges["finished"].Count);
		Debug.Log("Current thread [Completed] : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
		/*if(OnChallengesRetrieved != null){
			OnChallengesRetrieved(challenges);
		}*/


	}

Then I have this function for initializing the worker :

void InitWorker(){
		Debug.Log("Current thread [InitWorker] : " + System.Threading.Thread.CurrentThread.ManagedThreadId);
		bWorker = new BackgroundWorker();
		bWorker.DoWork += new DoWorkEventHandler(Worker_DoWork);
		bWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
	}

And I also have this JSONTask class to encapsulate the parsing task :

public class JSONTask {

	public string toParse;

	public JSONNode Parse(){
		return JSON.Parse(toParse);
	}
}

Now the output of this is not really what I expect :

Current thread [Main] : 1
Current thread [InitWorker] : 1
Current thread [Work] : 5
Current thread [AfterStartBackground] : 1
Challenges retrieved ! Waiting : 18 Ready : 5 Finished : 5
Current thread [Completed] : 2

So the completed is not back on the main thread, and it’s not even on the worker thread either.
If I launch this whole process once more I get the completed on the same worker thread but still not going back to main thread.

Everything I read about background workers says it should go back to the thread it was created in, but that is simply not the case here and I have no idea why. Please help me :smiley:

It sounds like there may be issues using BackgroundWorkers when a Form isn’t available. Looking at the comments under the documentation for the 2.0 framework:

If you have a class that uses
BackgroundWorker objects and want to
do unit tests on the class using VS
unit testing framework - you need to
instantiate a Form object - otherwise
the RunWorkerComplete event will
happen in random threads as opposed to
the expected main thread.

That’s in the context of unit testing, but I would imagine that would be an issue in any case where you don’t have the Form object.