Reputation: 20378
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
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
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
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
Reputation: 827208
What about using the System.Threading.Timer
Class on separate thread?
Upvotes: 1
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