2

I need to enqueue items into a Queue at roughly 4 to 8ms intervals.

Separately, my UI layer needs to dequeue, process, and display info from these items at roughly 33ms intervals (it may dequeue multiple times at that interval).

I'm not quite sure what combination of Timers and Queue I should use to get this working.

I think I should user the ConcurrentQueue class for the queue, but what timer mechanism should I use for the Enqueueing and Dequeuing?

UPDATE: I ended up going with something like Brian Gideon's and Alberto's answers.

Without going into all the details here is what I did:

I used the following timer to for both my 4ms timer and my 33ms timer. (http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer)

My 4ms timer reads data from a high speed camera, does a small amount of processing and enqueues the data into a ConcurrentQueue.

My 33ms timer dequeues all items from the queue, does some more processing on each item and sends the data to another object that computes a rolling average over some given interval. (Queues are used to manage the rolling averages.)

Within the CompositionTarget.Rendering event, I grab the value(s) from the rolling average object and plot them on my custom line graph control.

I mentioned 33ms for the UI because this data is being fed into a realtime graph. 33ms is about 30 fps... anything slower than that and some smoothness is lost.

I did end up using the ConccuentQueue as well. Works great.

CPU takes a bit of a hit. I think it's due to the high performance timers.

Thanks for the help everyone.

Jeff Weber
  • 949
  • 1
  • 8
  • 18

3 Answers3

1

You can use one DispatcherTimer for dequeue elements and publish them to the UI and another Timer to enqueue.

For example:

class Producer
{
    public readonly Timer timer;
    public ConcurrentQueue<int> Queue {get;private set;}

    Producer()
    {
        timer = new Timer(Callback, null, 0, 8);
        Queue = new Concurrent<int>();
    }

    private void Callback(object state)
    {
        Queue.Enqueue(123);
    }
}

class Consumer
{
    private readonly Producer producer;
    private readonly DispatcherTimer timer;

    Consumer(Producer p)
    {
        producer = p;
        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromMilliseconds(33);
        timer.Tick += new EventHandler(dispatcherTimer_Tick);
        timer.Start();
    }

    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        int value;
        if(producer.Queue.TryDequeue(out value))
        {
            // Update your UI here
        }
    }
}
Alberto
  • 15,626
  • 9
  • 43
  • 56
  • If you use a normal timer, the event will be fired in another thread than the UI's one. Either the queue is designed for concurrency, or the simplest way is using two DispatcherTimer, which are guaranteed to works on the same thread, that is the UI. – Mario Vernari Sep 21 '13 at 15:51
  • @MarioVernari using a ConcurrentQueue you can enqueue items from a normal timer and dequeue them in a dispatcher timer. I added an example. – Alberto Sep 21 '13 at 18:17
  • That's what I said. However, I think Jeff should go native because the reliability of any kind of manager timer won't fall in the expected range. – Mario Vernari Sep 22 '13 at 04:28
  • Thanks, for the sample code, Alberto. I'll probably implement this first with a .Net timer and see if I can get by with it. If not I'll have to look at one of the high perf. timers that wrap the Win32 timers. Should still be able to use the DispatchTimer from Dequeue because my UI only needs to read data at ~33ms. I will be able to Dequeue 4 items at a time. – Jeff Weber Sep 23 '13 at 12:01
1

Those are some really tight timing requirements. I question the ~33ms value for the UI updates. The UI should not have to be updated any faster than a human can perceive it and even then that is probably overkill.

What I would do instead is to use a producer-consumer pipeline.

Producer -> Processor -> UI

In my primitive illustration above the Producer will do the step of generating the messages and queueing them. The processor will monitor this queue and do the non-UI related processing of the messages. After processing is complete it will generate messages with just enough information required to update the UI thread. Each step in this pipeline will run on a designated thread. I am assuming you do have a legitimate need for two distinct intervals (4ms and 33ms respectively). I am suggesting you add a 3rd for the UI. The polling intervals might be:

~4ms -> ~33ms -> 500ms

I used the tilde (~) intentionally to highlight the fact that lower interval timings are very hard to achieve in .NET. You might be able to hit 33ms occassionally, but the standard deviation on an arbitrary population of "ticks" will be very high using any of the timers built into the BCL. And, of course, 4ms is out of the question.

You will need to experiment with multimedia timers or other HPET (high performance event timer) mechanisms. Some of these mechanisms use special hardware. If you go this route then you might get closer to that 4ms target. Do not expect miracles though. The CLR is going to stack the deck against you from the very beginning (garbage collection).

See Jim Mischel's answer here for a pretty good write up on some of your options.

Community
  • 1
  • 1
Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
0

Since you are dealing with the UI, you could use a couple of DispatcherTimer instead the classic timers. This timer is designed just for the interaction with the UI, thus your queue should be able to enqueue/dequeue without any problem.

Mario Vernari
  • 6,649
  • 1
  • 32
  • 44
  • It was my understanding, though, that the DispatcherTimer could not be guaranteed to run at 4 to 8ms. It's important that I can enqueue at that rate otherwise I will miss data. – Jeff Weber Sep 21 '13 at 17:47
  • In a managed world (i.e. .Net) there's no guarantee for accurate timings, and that's not related to this or that kind of timer. However, (1) the DispatcherTimer has a parameter to set its priority, and (2) the UI thread is one of the most privileged. Honestly, I never measured the reliability of the PC timers, but it's an easy task for you. Otherwise, you should go native, and write your program (or part of it) in C/C++. – Mario Vernari Sep 22 '13 at 04:11
  • You're right. I wasn't able to run the DispatcherTimer faster than 64 ticks per seconds (about 15 ms). So your only chance is going native, but...since the DispatcherTimer is driven by the UI processor, even running faster, how could you manage a so fast data incoming? – Mario Vernari Sep 22 '13 at 04:56