Nippysaurus
Nippysaurus

Reputation: 20378

executing code at precise intervals

I have a list of data and the time(s) at which it needs to be processed. The times are usually about one second (or less) apart (they vary) but needs to be run fairly close to that time. I have tried putting the thread to sleep for a small amount of time but there is a bit of overhead associated with resuming a thread after sleeping which causes a short delay. Is there a reliable way to get the accuracy that I need with relatively simple code?

Upvotes: 0

Views: 410

Answers (5)

stacked
stacked

Reputation: 68

Try using a StopWatch object. I created a hypothetical DataAndTime object

public class DataAndTime
{   
   private string m_Data = "";
   public string Data {
      get { return m_Data; }
      set { m_Data = value; }
   }

   private int m_TimeInMilliSeconds = 0;
   public int TimeInMilliSeconds {
      get { return m_TimeInMilliSeconds; }
      set { m_TimeInMilliSeconds = value; }
   } 
}

where TimeInMilliSeconds is the precise interval in milliseconds between which you want to process the list of data. I then created two objects, a stack and a stopwatch:

private Stack<DataAndTime> aStack = new Stack<DataAndTime>();    
private Stopwatch aStopWatch = new Stopwatch()

You can use a collection or list instead of a stack or whatever. I populate the stack with 100 DataAndTime objects:

public void PopulateStack{
    for (int Index = 0; Index <= 100; Index++) {
        DataAndTime NewDataAndTime = new DataAndTime();
        NewDataAndTime.Data = (string)Index + " AS A STRING";
        NewDataAndTime.TimeInMilliSeconds = 1000 - Index;
        aStack.Push(NewDataAndTime);
    }
 } 

The idea is the same as the physical analogue of stopping and starting a stop watch, and not doing something until the relevant time in elapsed milliseconds has passed. Voila. Total about 40 lines of code:

 public void ProcessData{
 {
     while (aStack.Count > 0) {
         aStopWatch.Reset();
         aStopWatch.Start();
         DataAndTime StackPop = aStack.Pop;
         string CallBackData = StackPop.Data;
         int CallBackTime = StackPop.TimeInMilliSeconds;
         while (aStopWatch.ElapsedMilliseconds < CallBackTime) {
         }
         Console.WriteLine("Time elapsed for " + CallBackData + " " + CallBackTime + ":  " + aStopWatch.ElapsedMilliseconds);
         aStopWatch.Stop();
     }
 }

Upvotes: 1

Mark Rushakoff
Mark Rushakoff

Reputation: 258138

The most reliable way to start processing at the exact time you want, would be to block until the exact time. In pseudocode:

futuretime = now + 1 second;
while (now < futuretime)
{
     // do nothing
}
// 1 second has elapsed, start processing

But of course, this will hog the CPU as long as you're in the while loop.

Or you could come halfway, and do a thread-sleep until you're within, say, 50+ milliseconds of your target time, and only then do a blocking wait. You won't hog the CPU as much, and you can be reasonably sure that your thread will be activated before the 1-second time arrives.

This article has a very thorough evaluation of the timing functions offered by the Windows API. At the end, it concludes:

... consider a hybrid scheme, where you call Sleep(1) ... whenever you need to pass more than 1 ms of time, and then only enter the QueryPerformanceCounter 100%-busy loop to finish off the last < 1/1000th of a second of the delay you need. This will give you ultra-accurate delays (accurate to 10 microseconds), with very minimal CPU usage.

Upvotes: 0

James Black
James Black

Reputation: 41858

If you absolutely need to keep a short duration of difference in timing, you may want to look at using the DirectX API. DirectX 9.0c has a Managed .NET interface, and it gives you access to a high-reliability clock. I had used this playing some music where I had less than 1ms to start and stop music and this worked well.

But, the application will take over the computer, as sharing will throw your timing off, then you might as well be using the Timer.

Upvotes: 0

Christian C. Salvad&#243;
Christian C. Salvad&#243;

Reputation: 827208

What about using the System.Threading.Timer Class on separate thread?

Upvotes: 1

RossFabricant
RossFabricant

Reputation: 12492

In a multi-tasking operating system boosting the priority of your process can help, but unless it your OS supports real time you can't make timing guarantees with precision on the level of a few milliseconds.

Upvotes: 2

Related Questions