- Home /
Blocking method calls in a coroutine?
Can blocking calls be used in a coroutine without it stopping the main thread? I have a MonoBehaviour that is designed to send a UDP broadcast to obtain a server IP address on LAN that is listening for the broadcast. In my coroutine, I'm executing a UDPClient.Recieve
method to get back a message, and it seems to be halting my main thread entirely despite my correct use of yield
statements.
UdpClient client = new UdpClient();
Coroutine discoverAddress;
IEnumerator DiscoverAddress (
float timeout,
OnAddressDiscovered onAddressDiscovered,
OnTimeout onTimeout
) {
float timeWaited = 0;
yield return null;
for (;;) {
if (timeWaited >= timeout) break;
string address = AskForAddress();
if (address != null || address != "") {
onAddressDiscovered(address);
StopCoroutine(discoverAddress);
}
timeWaited += Time.deltaTime;
yield return null;
}
onTimeout();
client.Close();
}
string AskForAddress () {
IPEndPoint serverEp = new IPEndPoint(IPAddress.Any, 0);
client.EnableBroadcast = true;
byte[] requestData = Encoding.ASCII.GetBytes("SomeRequestData");
client.Send(
requestData,
requestData.Length,
new IPEndPoint(IPAddress.Broadcast, udpPort)
);
byte[] serverResponseData = client.Receive(ref serverEp);
string serverResponse = Encoding.ASCII.GetString(serverResponseData);
return serverEp.Address.ToString();
}
Answer by Bunny83 · Jun 05, 2020 at 09:44 AM
No, they can not be used since a coroutine is a "cooperative routing" which runs on the main thread and requires cooperation by the routine in order to keep the the rest of the code in the thread running. When the execution is yielded to your coroutine, your coroutine is the only thing running at that moment (of course on the main thread only). Other parts of the main thread can only continue when your coroutine uses the yield statement at which point your coroutine is essentially suspended and the execution is yielded back to Unity. As long as you don't yield your main thread is stuck in your coroutine.
Any kind of direct networking has to be done on a seperate thread. You can use something like the Loom class of WhyDoIDoIt which allows you to easily schedule a method / lambda expression / delegate on a seperate thread and also provides a way to schedule a method / lambda expression / delegate back on the main thread. So you can simply do something like:
Loom.RunAsync(()=>{
// this will be executed on a seperate thread
// Run your blocking code here
// when done and you have your result you can schedule the following
// lambda back on the main thread:
Loom.QueueOnMainThread(()=>{
// this will be executed on the main thread
onAddressDiscovered(address);
});
});