Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Properly Use Realtime Priority

My question may not really be about realtime processing, but then again, it may be.

My application has several threads that are far more important than the GUI, BUT, I do want the GUI to at least be usable. I don't want it locked at all times, and I do want to update the screen given results of processing I am performing.

Currently all my essential items are isolated in separate threads, and I call a delegate to my GUI to display results.

My GUI works, but if I change tabs, or minimize/maximize it, it has been known to hinder my other threads to the point where they can not perform their operations within the 0.1s time limit they are held to.

This is what I am doing to call my delegate:

delegate void FuncDelegate(ResultContainer Result);
FuncDelegate DelegatedDisplay= new FuncDelegate(DisplayResults);
//then later on
Invoke(DelegatedDisplay, Result);

Most of my critical processes are threads that run in continuous loops, pulling from and pushing to various buffers (ArrayLists and normal Lists).

One of my critical threads is launched every time, using:

Thread mythread = new Thread(new ThreadStart(ProcessResults));
mythread.Start();

The reason I thought to do this, instead of just having a thread running in a loop, pulling from lists, is that I thought perhaps the reason I was running out of clock time was that I have a polling loop that I worry consumes too many resources (although I am using Thread.Sleep(5) every time the poll turns up negative).

Does launching a new thread each time I need the concurrent process cost me valuable time? Should this be a loop? Are my loops to blame?

Can I give a thread higher priority than others, or is the use of Thread.Sleep my only option? If I do assign higher thread priorities, how can I be sure other threads can even survive?

Why are simple forms events hampering my other threads so much? Is there a way to give my GUI thread an assigned, lower amount of resources? Can I use a Thread.Sleep somehow to block Form events if the other threads are running out of clock time?

Short of an answer to all my frustrating questions, is there some kind of thread profiler I can be using to help figure my mess out? I tried using "Managed Stack Explorer" but somehow that doesn't always show what threads my application has.

Any help on this matter would help me greatly.

like image 320
Gorchestopher H Avatar asked May 31 '12 13:05

Gorchestopher H


2 Answers

Well here's a start:

Invoke(DelegatedDisplay, Result);

This means that you are causing the background thread to wait until the UI thread actually performs the drawing operation, then proceed. From the thread's point of view that's an eternity. You might want to investigate asynchronous updates to the UI:

BeginInvoke(DelegatedDisplay, Result);

That's equivalent to telling the UI thread "when you have a chance, perform this drawing action", then proceeding with the work that you were doing.

You should be aware that this may cause thread-safety issues that didn't occur using Invoke, though. For example, if the background thread is still modifying Result while the UI is attempting to draw, you might have unexpected race conditions.

See Control.Invoke vs Control.BeginInvoke

like image 104
Chris Shain Avatar answered Sep 28 '22 07:09

Chris Shain


Using marshaling techniques like Invoke and BeginInvoke to update the UI is part of the problem. In fact, I rarely use marshaling operations for the UI and worker thread interactions because it is not that great of a solution. Well, to be frank, it can be (and usually is) the worst solution in most cases of this nature.

What I typically do is have the worker thread publish its results or progress to a shared data structure and have the UI thread poll for it using a System.Windows.Forms.Timer (or DispatcherTimer) on an interval that is tuned to work best for the situation at hand.

Here is what it might look like.

public class YourForm : Form
{
  private ConcurrentQueue<ResultContainer> results = new ConcurrentQueue<ResultContainer>();

  public UpdateTimer_Tick(object sender, EventArgs args)
  {
    // Limit the number of results to be processed on each cycle so that
    // UI does not stall for too long.
    int maximumResultsToProcessInThisBatch = 100;

    ResultContainer result;
    for (int i = 0; i < maximumResultsToProcessInThisBatch; i++)
    {
      if (!results.TryDequeue(out result)) break;
      UpdateUiControlsHere(result);
    }
  }

  private void WorkerThread()
  {
    while (true)
    {
      // Do work here.
      var result = new ResultContainer();
      result.Item1 = /* whatever */;
      result.Item2 = /* whatever */;
      // Now publish the result.
      results.Enqueue(result);
    }
  }
}

The thing is, people have been so programmed to automatically use Invoke or BeginInvoke to update the UI that they ignore better solutions. It has gotten to the point where these marshaling techniques fit into the realm of cargo cult programming. I probably sound like a broken record regarding this topic because I rip on it all of the time. The technique I used above has the following advantages.

  • It breaks the tight coupling between the UI and worker threads that the marshaling operations impose.
  • The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
  • There is no chance of saturating the UI message queue as would be the case with BeginInvoke.
  • You get more throughput on both the UI and worker threads.
  • The UI thread gets to dictate when and how often the UI thread should be updated.
  • You do not have to litter your code (and I mean that quite literally) with Invoke or BeginInvoke calls.
  • Marshaling operations are expensive.
  • The code ends up looking more elegant.

Does launching a new thread each time I need the concurrent process cost me valuable time? Should this be a loop? Are my loops to blame?

I would avoid creating threads willy-nilly. If you can keep the thread running in a loop that would be better.

Can I give a thread higher priority than others, or is the use of Thread.Sleep my only option? If I do assign higher thread priorities, how can I be sure other threads can even survive?

Giving your worker thread a higher priority would probably help in this case. Thread.Sleep(5) will not sleep for 5ms though. It just does not work that way. By the way there are some special values that you can pass to Thread.Sleep.

  • Thread.Sleep(0) yields to any thread with the same or higher priority on any processor.
  • Thread.Sleep(1) yields to any thread on any processor.

Why are simple forms events hampering my other threads so much? Is there a way to give my GUI thread an assigned, lower amount of resources? Can I use a Thread.Sleep somehow to block Form events if the other threads are running out of clock time?

It is because you are using Invoke. Avoiding the marshaling operations will help significantly since it decouples the threads. Do not use Thread.Sleep on the UI thread. The UI thread must remain unblocked for it to work properly. If you use the solution I propose above then it is much easier to throttle the UI thread.

like image 31
Brian Gideon Avatar answered Sep 28 '22 07:09

Brian Gideon