- Home /
Callback from a coroutine
I'm building a C# API for various network services. Currently my methods need to be polled to return data, but I'd like to upgrade this to have them trigger a developer-implemented callback.
I've established after some research that it is not safe to trigger a callback from a separate thread back into the main UnityEngine/MonoBehavior thread.
So my next thought - perhaps I can have my API take in the developer callback, start a coroutine but return immediately after, and eventually trigger the callback from the coroutine. I'm hoping to vet this idea before going too far down the rabbit hole, so I'll paste my proposed code below (somewhat pseudo) and if anyone has feedback as to whether or not this would be safe I'd greatly appreciate it.
Here is the example class that would contain the API:
using UnityEngine;
using System.Collections;
public class DoAsynchronousStuff : MonoBehaviour
{
enum State {Pending, Complete};
State state;
// assume OutputData and InputData are classes defined elsewhere
public delegate void Callback (OutputData data);
public static void DoAThing(InputData data, Callback cb)
{
StartCoroutine(DoIt(data, cb));
}
IEnumerator DoIt(InputData data, Callback callBack)
{
/* would be state machine here that hits a web service
* or something and updates state to Complete when a
* response is received (and populates an OutputData) */
while (state != Complete)
yield;
callBack(outputData);
}
}
Then the developer implementation would look something like:
using UnityEngine;
using System.Collections;
public class Sample : MonoBehaviour
{
OutputData outputData = null;
InputData inputData;
DoAsynchronousStuff.Callback myCallback = DidAThing;
void DidAThing(OutputData data)
{
outputData = data;
}
void Start()
{
// assume we've populated inputData already
DoAsynchronousStuff.DoAThing(inputData, myCallback);
}
void Update()
{
if (outputData != null)
{
// do stuff with the data
outputData = null; // so we only do stuff with data once
}
}
}
I was searching for a solution like yours, but unfortunately your code dosen't work if i use it the way it is. Unity gives me the following Errors: "error CS0201: Only assignment, call, increment, decrement, and new object expressions can be used as a statement" I then changed "yield;" to "yield return null;" and this error disappeard. Then came: "error CS0120: An object reference is required to access non-static member `UnityEngine.$$anonymous$$onoBehaviour.StartCoroutine(System.Collections.IEnumerator)'"
Can you help me get this to work?
We had a similar issue to this where a third party library would fire callbacks not on the main thread, which would cause some tricky bugs. Our solution was essentially what you've got here - some sort of shared data set by the callback, which could then be checked by the main thread in a coroutine. So far, this has worked fine for us, so I'd say this looks solid.
Nice thing about a coroutine like that is you could also easily create time-out scenarios or use a timer to detect when a network operation is taking too long, and respond to it.
Answer by edcarlo · Jan 07, 2014 at 07:11 AM
StartCoroutine & DoIt is a non-static. So DoAThing(...) must be non-static.
Your answer
Follow this Question
Related Questions
C# lambda call in for loop references to last object 3 Answers
Coroutines, Threads and Level Generation? 2 Answers
C# How to wait on callback, should I use threading? 1 Answer
Is there any workaround to run corutines in an other thread? 1 Answer
Does UnityEngine.CustomeYieldInstruction works in a seperate thread? 2 Answers