How to do something every millisecond or better on Windows

This question is not about timing something accurately on Windows (XP or better), but rather about doing something very rapidly via callback or interrupt .

I need to be doing something regularly every 1 millisecond, or preferably even every 100 microseconds. What I need to do is drive some assynchronous hardware (ethernet) at this rate to output a steady stream of packets to the network, and make that stream appear to be as regular and synchronous as possible. But if the question can be separated from the (ethernet) device, it would be good to know the general answer.

Before you say "don't even think about using Windows!!!!", a little context. Not all real-time systems have the same demands. Most of the time songs and video play acceptably on Windows despite needing to handle blocks of audio or images every 10-16ms or so on average. With appropriate buffering, Windows can have its variable latencies, but the hardware can be broadly immune to them, and keep a steady synchronous stream of events happening. Even so, most of us tolerate the occasional glitch. My application is like that - probably quite tolerant.

The expensive option for me is to port my entire application to Linux. But Linux is simply different software running on the same hardware, so my strong preference is to write some better software, and stick with Windows. I have the luxury of being able to eliminate all competing hardware and software (no internet or other network access, no other applications running, etc). Do I have any prospect of getting Windows to do this? What limitations will I run into?

I am aware that my target hardware has a High Performance Event Timer, and that this timer can be programmed to interrupt, but that there is no driver for it. Can I write one? Are there useful examples out there? I have not found one yet. Would this interfere with QueryPerformanceCounter? Does the fact that I'm going to be using an ethernet device mean that it all becomes simple if I use select() judiciously?

Pointers to useful articles welcomed - I have found dozens of overviews on how to get accurate times, but none yet on how to do something like this other than by using what amounts to a busy wait. Is there a way to avoid a busy wait? Is there a kernel mode or device driver option?


You should consider looking at the Multimedia Timers. These are timers that are intended to the sort of resolution you are looking at.

Have a look here on MSDN.


I did this using DirectX 9, using the QueryPerformanceCounter , but you will need to hog at least one core, as task switching will mess you up.

For a good comparison on tiemers you can look at

http://www.geisswerks.com/ryan/FAQS/timing.html


If you run into timer granularity issues, I would suggest using good old Sleep() with a spin loop. Essentially, the code should do something like:

void PrecisionSleep(uint64 microSec)
{
    uint64 start_time;

    start_time = GetCurrentTime(); // assuming GetCurrentTime() returns microsecs

    // Calculate number of 10ms intervals using standard OS sleep.
    Sleep(10*(microSec/10000)); // assuming Sleep() takes millisecs as argument

    // Spin loop to spend the rest of the time in
    while(GetCurrentTime() - start_time < microSec)
    {}
}

This way, you will have a high precision sleep which wouldn't tax your CPU much if a lot of them are larger than the scheduling granularity (assumed 10ms). You can send your packets in a loop while you use the high precision sleep to time them.

The reason audio works fine on most systems is that the audio device has its own clock. You just buffer the audio data to it and it takes care of playing it and interrupts the program when the buffer is empty. In fact, a time skew between the audio card clock and the CPU clock can cause problems if a playback engine relies on the CPU clock.

EDIT: You can make a timer abstraction out of this by using a thread which uses a lock protected min heap of timed entries (the heap comparison is done on the expiry timestamp) and then you can either callback() or SetEvent() when the PrecisionSleep() to the next timestamp completes.

链接地址: http://www.djcxy.com/p/54206.html

上一篇: Git子树或Git子模块的大型资源?

下一篇: 如何在Windows上每毫秒或更多时间做某些事情