Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I had a coroutine in Unity3D that downloaded a zip from a server, extracted it to the persistent data path, and loaded its contents into memory. The flow looked something like this:

IEnumerator LongCoroutine()
{
    yield return StartCoroutine(DownloadZip());
    ExtractZip();
    yield return StartCoroutine(LoadZipContent());
}

But the ExtractZip() method (which uses the DotNetZip library), is synchronous, takes too long, and leaves me no place to yield during the process.

This resulted in the application being killed (on mobile devices) whenever I tried to extract a large zip, which I assume is due to the main thread becoming unresponsive for too long.

Is this something that mobile OS are known to do (kill the app if a frame takes too long)?

So, I assumed that extracting the zip on a separate thread might solve the problem, and it seems to have worked. I created this class:

public class ThreadedAction
{
    public ThreadedAction(Action action)
    {
        var thread = new Thread(() => {
            if(action != null)
                action();
            _isDone = true;
        });
        thread.Start();
    }

    public IEnumerator WaitForComplete()
    {
        while (!_isDone)
            yield return null;
    }

    private bool _isDone = false;
}

And I use it like this:

IEnumerator LongCoroutine()
{
    yield return StartCoroutine(DownloadZip());
    var extractAction = new ThreadedAction(ExtractZip);
    yield return StartCoroutine(extractAction.WaitForComplete());
    yield return StartCoroutine(LoadZipContent());
}

But I'm still not sure if this is the best way to implement it, or if I need to lock _isDone (not too used to multithreading).

Can something go wrong with this / am I missing something?

share|improve this question

2 Answers 2

This is a really elegant solution for wrapping up multithreaded tasks in a coroutine, well done :)

Mixing coroutines and threads is perfectly safe, provided you correctly lock access to resources shared between your main thread (which the coroutine executes on) and the worker thread(s) you create. You shouldn't need to lock _isDone in any way, since it's only ever written to by the worker thread and there's no intermediate state that could cause the main thread to misbehave.

Where you do need to look out for potential problems, is if any resources are written to by ExtractZip and are either

  1. simultaneously written to by a function being called from your main thread or
  2. being read by a function on the main thread and expected to be in a safe state before ExtractZip completes.

In this particular case, my worry would be that if you don't check that you're not trying to download the same file to the same location twice, you could have two threads simultaneously running ExtractZip that interfere with one another.

share|improve this answer

Well, I'm not a major expert either, but I think in your 2nd example, the WaitForComplete() function will still block the calling thread until the ThreadedAction thread completes. What you can do is pass a callback function to your zip processing Thread, and have it call that function when it's done. That way your main thread starts the zip thread and then continues on doing his stuff (updating GUI, what have you), and then the call back function will set something in the main thread when it's done (like boolean zipDone=true), and at this point the main thread can react to that (display "Zip extracted" in the GUI etc).

share|improve this answer
    
It would appear so, but WaitForComplete is a Unity3D coroutine, so it only will run one iteration of the while loop every frame, then yields to let everything else in the game update. It's not blocking the thread :) –  David Gouveia Mar 13 '13 at 12:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.