Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speeding up realtime Gui updates from a thread

This is a technique I've used for years to receive network data and use it in my GUI (dialog, form etc).

    public delegate void mydelegate(Byte[] message);

    public ReceiveEngineCS(String LocalIpIn, String ReceiveFromIp, mydelegate d)
    {
         this.m_LocalIpIn = LocalIpIn;
         this.m_ReceiveFromIp = ReceiveFromIp;
         m_MainCallback = d;
         SetupReceive();
         m_Running = true;
         //Create the Track receive thread and pass the parent (this)
         m_RtdirReceiveThread = new Thread(new ParameterizedThreadStart(MessageRecieveThread));
         m_RtdirReceiveThread.Start(this);
    }

    private void MessageRecieveThread(System.Object obj)
    {
         ReceiveEngineCS parent = (ReceiveEngineCS)obj;

         while(parent.m_Running)
         {
              Byte[] receiveBytes = new Byte[1500];
              try
              {
                   receiveBytes = parent.m_ClientReceiver.Receive(ref parent.ipEndPoint);
                   parent.ThreadOutput(receiveBytes);   
              }
              catch ( Exception e )
              {
                  parent.StatusUpdate(e.ToString()); 
              }                         
         }          
    }

    public void ThreadOutput(Byte[] message)
    {
         m_MainCallback(message);           
    }

public partial class SystemMain : Form
{
    //Local Class Variables
    Network.ReceiveEngineCS SystemMessageReceiver;
    private void Form1_Load(object sender, EventArgs e)
    {
        //Load up the message receiver
        SystemMessageReceiver = new Network.ReceiveEngineCS(localAddy, fromAddy, new mydelegate(LocalDelegate));
    }

    public void LocalDelegate(Byte[] message)
    {
        if (Form.ListView.InvokeRequired)
        {
            //External call: invoke delegate
            Form.ListView.Invoke(new mydelegate(this.LocalDelegate), message);
        }
        else
        {
            //Get the Packet Header
            Formats.PacketHeaderObject ph = new Formats.PacketHeaderObject(message);
            //Update or Add item to Specific ListView
            ... update views
        }
    }
 }

The Receiver takes in anywhere between 10 and 100 real-time messages a second and often more.

I've been doing research lately into .Net 4.0 and C# and noticed many other similar ways to do this data processing ,such as Worker Threads, and other ways of using the Delegate and Invoke.

My question... Is there a more efficient way in the newer .Net Libraries (3.5, 4.0 etc) to do this data receive / GUI updating?

I think this method isn't working as well with C#.

Any help would be appreciated.

like image 898
Sleff Avatar asked Apr 24 '11 23:04

Sleff


2 Answers

One of the best ways of posting updates to a GUI is to have the worker thread package up the data included in the update and place it in a queue. The UI thread will then poll the queue periodically. Having the worker thread use Control.Invoke to update the UI is way overused in my opinion. In contrast, having the UI thread poll for the updates has several advantages.

  • It breaks the tight coupling between the UI and worker threads that Control.Invoke imposes.
  • It puts the responsibility of updating the UI thread on the UI thread where it should belong anyway.
  • The UI thread gets to dictate when and how often the update should take place.
  • There is no risk of the UI message pump being overrun as would be the case with the marshaling techniques initiated by the worker thread.
  • The worker thread does not have to wait for an acknowledgement that the update was performed before proceeding with its next steps (ie. you get more throughput on both the UI and worker threads).

You did not mention how ThreadOutput was implemented, but you might consider the approach I mentioned above if it is not already done that way. Experience has taught me that this is usually the best approach. Letting the UI thread throttle its update cycle is big a advantage.

like image 76
Brian Gideon Avatar answered Sep 20 '22 03:09

Brian Gideon


Take a look into Thread Pooling instead of spinning new thread each time.

like image 29
Zamboni Avatar answered Sep 21 '22 03:09

Zamboni