4
\$\begingroup\$

I have a GameObject that reads sensor data coming in over UDP (formatted as JSON).

What I am observing in that my handshake (dataReady) is getting cleared by the Update() cylcle fast enough, and I am logging "data overruns" (see the code below).

I have the GameLoop running at 150FPS (confirmed in the IDE) and messages are comming at 0.5 FPS (simulated). So I really am wondering about the thread interaction. (I tried an async UDP read earlier, and had the same issue, I figured this was safer.

For debug I tested to make sure that CarMover.moveme() is called. I can see that happening in VS2015.

What is really strange is that even though messages are only coming in at 0.5 Hz, and the game loop is running at 150FPS (which means update() should be clearling dataready all the time, it is not happening. Not even the first time. Really odd.

I am also now included the external blaster.cs code that I use to test the Unity, so you can try it yourself and see what is going on.

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System;
using System.Text;
using System.Net;
using System.Threading;

public class CommScript : MonoBehaviour
{
    UdpClient client;
    IPEndPoint endPoint;
    public int port = 7777;
    public string hostName = "localhost";
    public static Packet message;
    public static bool dataReady = false;
    public GameObject car;
    public int stepNum;
    Thread listener;
    public int upDateLoop = 0;

    void Start()
    {
        endPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], port);
        client = new UdpClient(endPoint);
        dataReady = false;
        Tools.LogDebug(gameObject.name, "Listening for Data...");
        listener = new Thread(new ThreadStart(translater));
        listener.IsBackground = true;
        listener.Start();
    }
    void Update()
    {
        if (dataReady)
        {
            upDateLoop++;
            stepNum = message.step;
            car.GetComponent<CarMover>().moveMe(message);
            dataReady = false;
        }
    }

    void OnApplicationQuit()
    {
        client.Close();
    }

    void translater()
    {
        Byte[] data = new byte[0];
        while (true)
        {
            try
            {
                data = client.Receive(ref endPoint);
                if (dataReady)
                {
                    Tools.LogDebugThread("Comm.translater", "DataOverrun", -1, -1);
                    client.Close();
                    return;
                }
            }
            catch (Exception err)
            {
                Tools.LogDebugThread("Comm.translater", "recieve data error " + err, -1, -1);
                client.Close();
                return;
            }
            string json = Encoding.ASCII.GetString(data);
            message = Packet.Parse(json);
            dataReady = true;
            //Tools.LogDebugThread("Comm", "got message: " + message.ToString(), 0, 0);
        }
    }
}

Blaster.cs

using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Timers;

namespace Blaster
{
    class Blaster
    {
        UdpClient client;
        IPEndPoint endPoint;
        public int port = 7777;
        public string hostName = "localhost";
        public int stepNum = 0;
        const int rate = 2000;
        public Timer clock;

        static void Main(string[] args)
        {
            Blaster b = new Blaster();
            b.run();
        }
        Blaster()
        {
            client = new UdpClient();
            endPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], port);
        }
        void run()
        {
            this.stepNum = 0;
            Console.WriteLine("Press Enter to do a send loop...\n");
            Console.ReadLine();
            Console.WriteLine("started at {0:HH:mm:ss.fff}", DateTime.Now);
            start();
            Console.WriteLine("Press Enter to stop");
            Console.ReadLine();
            stop();
            client.Close();
        }
        void stop()
        {
            clock.Stop();
            clock.Dispose();
        }
        void start()
        {
            clock = new Timer(rate);
            clock.Elapsed += send;
            clock.AutoReset = true;
            clock.Enabled = true;
        }
        void send(Object source, ElapsedEventArgs e)
        {
            Console.WriteLine("sending: {0}", stepNum);
            Byte[] sendBytes = Encoding.ASCII.GetBytes(message());
            try
            {
                client.Send(sendBytes, sendBytes.Length, endPoint);
            }
            catch (Exception err)
            {
                Console.WriteLine(err.ToString());
            }
        }
        string message()
        {
            Packet p = new Packet();
            p.id = "car";
            p.timestamp = DateTime.Now.ToString();
            p.x = 1.2f;
            p.y = 0.4f;
            p.z = 4.5f;
            p.step = stepNum++;
            string json = JsonConvert.SerializeObject(p);
            return json;
        }
    }
}
\$\endgroup\$
2
\$\begingroup\$

Well, I stumped our local unity expert also, but we did a debug session in my office and after about an hour, we found out it is not the code. The Unity IDE will report console messages even focus is off the window. But our test program was an external exe (Blaster.exe) which is a console program. So it looked like the messages were arriving and the update was not running. That was not the case, it was just that the IDE lost focus. I cleaned up my code to use a Synchrhonized Queue, so now all should be very thread safe.

BTW: The problem with IDE stopping running when it loses focus can be solved by:

    Application.runInBackground = true;

...

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System;
using System.Text;
using System.Net;
using System.Threading;

public class CommScript : MonoBehaviour
{
    UdpClient client;
    IPEndPoint endPoint;
    public int port = 7777;
    public string hostName = "localhost";
    public GameObject car;
    public int stepNum;
    Thread listener;
    Queue pQueue = Queue.Synchronized(new Queue()); // holds the packet queue

    void Start()
    {
        endPoint = new IPEndPoint(Dns.GetHostAddresses(hostName)[0], port);
        client = new UdpClient(endPoint);
        Tools.LogDebug(gameObject.name, "Listening for Data...");
        listener = new Thread(new ThreadStart(translater));
        listener.IsBackground = true;
        listener.Start();
    }
    void Update()
    {
        lock (pQueue.SyncRoot)
        {
            if (pQueue.Count > 0)
            {
                Packet p = (Packet)pQueue.Dequeue();
                stepNum = p.step;
                car.GetComponent<CarMover>().moveMe(p);
            }
        }
    }

    void OnApplicationQuit()
    {
        client.Close();
    }

    void translater()
    {
        Byte[] data = new byte[0];
        while (true)
        {
            try
            {
                data = client.Receive(ref endPoint);
            }
            catch (Exception err)
            {
                Tools.LogDebugThread("Comm.translater", "recieve data error " + err, -1, -1);
                client.Close();
                return;
            }
            string json = Encoding.ASCII.GetString(data);
            pQueue.Enqueue(Packet.Parse(json));
        }
    }
}
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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