Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Roggert · Oct 07, 2016 at 08:02 AM · c#crashwebglthreadingudp

UDP with coroutines crashing unity?

I'm working on a routine to receive UDP packets from an app. The system works fine when I use threading but using co-routines seems to just crash the editor outright on play! Any assistance would be welcomed. Someone suggested that it may be effecting the main thread of the program.

This is the script that crashed the editor.

using UnityEngine; using System.Collections; using System; using System.Text; using System.Net; using System.Net.Sockets; //using System.Threading; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary;

public class UdpScript : MonoBehaviour {

 struct MyData
 {
     public char letters;
     public byte byt;
     public float dudX, dudY, dudZ;
     public float NewX, NewY, NewZ;

     public MyData Deserialize(byte[] data)
     {
         MyData result = new MyData();

         using (MemoryStream inputStream = new MemoryStream(data))
         using (BinaryReader reader = new BinaryReader(inputStream))
         {
             this.letters = reader.ReadChar();
             this.letters = reader.ReadChar();
             this.byt = reader.ReadByte();
             this.byt = reader.ReadByte();
             this.dudX = reader.ReadSingle();
             this.dudY = reader.ReadSingle();
             this.dudZ = reader.ReadSingle();
             this.NewX = reader.ReadSingle();
             this.NewY = reader.ReadSingle();
             this.NewZ = reader.ReadSingle();
         }
         return result;
     }
 }

 //private Thread receiveThread;
 private UdpClient udp;
 private bool showData, LoopHold, UdpBool;
 public bool receivingbool;
 public int port;
 public float GyroX, GyroY, GyroZ, AccelX, AccelY, AccelZ, pitch, roll;

 // Use this for initialization
 void Start()
 {
     init();
     initUDP();
 }

 // Update is called once per frame
 void Update()
 {
     //StartCoroutine("TestCo");
     if (Input.GetKeyDown(KeyCode.U))
         UdpBool = !UdpBool;
     while (LoopHold)
         if (UdpBool)
             StartCoroutine("RecieveData");
     if (Input.GetKeyDown(KeyCode.D))
         showData = !showData;
 }

 //initialise values
 void init()
 {
     receivingbool = false;
     showData = false;
     LoopHold = true;
     UdpBool = false;
 }

 //initialise the Udp thread to read data
 void initUDP()
 {
     port = 9900;
     udp = new UdpClient(port);
     //receiveThread = new Thread(new ThreadStart(ReceiveData));
     //receiveThread.IsBackground = true;
     //receiveThread.Start();
 }

 //Display wether part is reciveing data from the digital twin and the accel values for caliration
 void OnGUI()
 {
     if (showData)
     {
         Rect rectObj = new Rect(5, 5, 100, 100);
         GUIStyle style = new GUIStyle();
         style.alignment = TextAnchor.UpperRight;
         GUI.Box(rectObj, "# UDPReceive: port :\n" + port + " #\n"
                 + "\nRecieving Data \n" + receivingbool + " \n"
                 + AccelX + "\n"
                 + AccelY + "\n"
                 + AccelZ, style);   //receivingbool is set when a new udp client starts.
     }
 }

 void ReadKeyInputs()
 {
     if (Input.GetKeyDown(KeyCode.D))
         showData = !showData;
 }

 // receive thread
 IEnumerator RecieveData()
 {
       try
       {
         IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
         byte[] data = udp.Receive(ref anyIP);
         MyData latestPacket = new MyData();
         latestPacket.Deserialize(data);
         GyroX = latestPacket.NewX;
         GyroY = latestPacket.NewY;
         GyroZ = latestPacket.NewZ;
         AccelX = latestPacket.dudX;
         AccelY = latestPacket.dudY;
         AccelZ = latestPacket.dudZ;
       }
       catch (Exception err)                                       //basic error handling, not particularly robust
       {
           print(err.ToString());
       }
         yield return null; 
 }

 IEnumerator TestCo()
 {
     Debug.LogWarning("tips");
     yield return null;
 }

 //close the UdpClient
 public void EndClient()
 {
     if (receivingbool)
     {
         //if (receiveThread.IsAlive)
         //    receiveThread.Abort();                      //Stop the curent thread
         udp.Close();                                //Close the whole client to avoid memory leaks 
         udp = null;
     }//set the address off the previous client to null
     LoopHold = false;
 }

}

I'm using co-routines as WebGL and Unity aren't thread-safe.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image doublemax · Oct 07, 2016 at 08:07 AM 1
Share
    while (LoopHold)
          if (UdpBool)
              StartCoroutine("RecieveData");

This loop creates new CoRoutines unti "LoopHold" becomes false. Is that what you intended?

In any case, you should never block the main thread by waiting for something. No matter how long it takes.

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Roggert · Oct 07, 2016 at 09:48 AM

Thank you @doublemax that helped quite a bit. still crashing however. here is an update version of the code. if anyone has any advice its welcome.

public class UdpScript : MonoBehaviour {

 struct MyData
 {
     public char letters;
     public byte byt;
     public float dudX, dudY, dudZ;
     public float NewX, NewY, NewZ;

     public MyData Deserialize(byte[] data)
     {
         MyData result = new MyData();

         using (MemoryStream inputStream = new MemoryStream(data))
         using (BinaryReader reader = new BinaryReader(inputStream))
         {
             this.letters = reader.ReadChar();
             this.letters = reader.ReadChar();
             this.byt = reader.ReadByte();
             this.byt = reader.ReadByte();
             this.dudX = reader.ReadSingle();
             this.dudY = reader.ReadSingle();
             this.dudZ = reader.ReadSingle();
             this.NewX = reader.ReadSingle();
             this.NewY = reader.ReadSingle();
             this.NewZ = reader.ReadSingle();
         }
         return result;
     }
 }

 //private Thread receiveThread;
 private UdpClient udp;
 private bool showData, UdpBool;
 public bool receivingbool;
 public int port;
 public float GyroX, GyroY, GyroZ, AccelX, AccelY, AccelZ;

 // Use this for initialization
 void Start()
 {
     init();
     initUDP();
 }

 // Update is called once per frame
 void Update()
 {
     StartCoroutine("RecieveData");
     if (Input.GetKeyDown(KeyCode.D))
         showData = !showData;
     if (Input.GetKeyDown(KeyCode.R))
         receivingbool = !receivingbool;
 }

 //initialise values
 void init()
 {
     receivingbool = false;
     showData = false;
 }

 //initialise the Udp thread to read data
 void initUDP()
 {
     port = 9900;
     udp = new UdpClient(port);
 }

 //Display wether part is reciveing data from the digital twin and the accel values for caliration
 void OnGUI()
 {
     if (showData)
     {
         Rect rectObj = new Rect(5, 5, 100, 100);
         GUIStyle style = new GUIStyle();
         style.alignment = TextAnchor.UpperRight;
         GUI.Box(rectObj, "# UDPReceive: port :\n" + port + " #\n"
                 + "\nRecieving Data \n" + receivingbool + " \n"
                 + AccelX + "\n"
                 + AccelY + "\n"
                 + AccelZ, style);   //receivingbool is set when a new udp client starts.
     }
 }

 // receive thread
 IEnumerator RecieveData()
 {
     if (receivingbool)
     {
         try
         {
             IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
             byte[] data = udp.Receive(ref anyIP);
             MyData latestPacket = new MyData();
             latestPacket.Deserialize(data);
             GyroX = latestPacket.NewX;
             GyroY = latestPacket.NewY;
             GyroZ = latestPacket.NewZ;
             AccelX = latestPacket.dudX;
             AccelY = latestPacket.dudY;
             AccelZ = latestPacket.dudZ;
         }
         catch (Exception err)                                       //basic error handling, not particularly robust
         {
             print(err.ToString());
         }
      }
      yield return null;
 }

 //close the UdpClient
 public void EndClient()
 {
    udp = null;                                //set the address off the previous client to null 
    udp.Close();                                //Close the whole client to avoid memory leaks 
 }

}

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image doublemax · Oct 07, 2016 at 10:12 AM 1
Share

You're still creating a new Coroutine in every Update() as soon as "receivingbool" becomes true. I'm not 100% which logic you want to achieve, but maybe something like this?

 if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.R))
 {
   receivingbool = !receivingbool;
   
   if( receivingbool )
     StartCoroutine("RecieveData");
   else
     StopCoroutine("RecieveData");
 }

Also, i have never used UdpClient, but from what i've read, Receive() is a blocking call, so it's unsuitable in a single-threaded application.

I found BeginReceive() which works asynchronously with a callback: https://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive(v=vs.110).aspx

If that works, you may not even need a Coroutine for this.

avatar image NoseKills · Oct 07, 2016 at 11:00 AM 0
Share
 // receive thread
  IEnumerator RecieveData()...

Coroutines run on the main thread. They cannot be used as a substitute for threads. The only performance benefit they offer is, you can use yield return to break up the actions inside the IEnumerator so that this one method executes over multiple frames.

Your IEnumerator method has one yield return at the end of the method where the method would return in any case. It's really just a normal method this way.

Whichever method you use (i.e. BeginReceive and a callback as @doublemax suggested), remember that Unity won't allow for example creating GameObjects from your own threads so read the received messages into a collection ( in the callback ) and use them from there in the Update of some $$anonymous$$onobehaviour if you do "anything Unity" with them

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

7 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Distribute terrain in zones 3 Answers

Multiple Cars not working 1 Answer

Unity to Node.js UDP: datagrams received are all empty. 2 Answers

Unity Jobs Unknown Length of NativeArray 0 Answers

Unity WebGL form posts to Cloud Firestore with Firebase JS SDK 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges