2

I need to implement an update loop in C# similar to an update loop in a game engine which periodically executes a sequence of tasks. I already searched for some documentation googling around and reading some SO discussions and THIS from game programming patterns, however my situation may be a little different and I didn't really found a solution to my problem. Here's my situation:

1- The update loop must process its tasks up to 1000 times per second (1000 is not an hard constraint, if the loop runs 999 or 1001 it would be fine anyway)

2- Tasks are synchronous, so if I have task1 that requires 100 seconds to execute, task2 will wait 100 seconds

3- The program executes only on Windows, so If needed I can use PInvoke to call Windows native functions

4- It's ok if the thread that starts the loop is the same that executes it and stays blocked inside it

5- The loop must not consume the entire core if there are no jobs to do or if the jobs can be processed faster than 1000 times per second. Basically the loop can sleep / wait if it needs to (more on this later)

I found here HERE a solution which implements an event loop in C#, however tasks there are asynchronous and it violates point 2.

I also found HERE a solution which uses System.Timers.Timer to execute a task.

HOWEVER:

Windows is not a realtime OS and timers have a frequency of about 15ms by default, which means about just 66 updates per second.

I know from HERE that timers can be set to 1ms, but since the setting is global it can create problems with other programs and if possible i would like to avoid this.

Finally I saw HERE that I can use Windows message pump to fire my updates using the Idle event, but I didn't found if it can be fired up to 1000 times or if it has side effects like generating garbage.

So far I have thought about these "solutions" (that are not valid since they violate points 1 or 5)

while(isRunning)
{
   startTime = stopWatch.Elapsed;

   ProcessTasks();

   Thread.sleep(timeToWait - (stopWatch.Elapsed - startTime)); //variant below
}

But since the default minimum sleep time is about 15ms (or far more than 1ms anyway) Thread.sleep can't be used, so i tried

while ((stopTicks = this.stopWatch.ElapsedTicks - startTicks) < this.sleepTicks)
{
   Thread.SpinWait(x); //OR Thread.Yield();
}

Where x is a variable that ensures enough precision and using constants inside Timespan struct I can convert ticks in milliseconds or another time unit and make the loop execute 1000 times per second. However this approach ends up consuming an entire core (100% core usage) which is bad since this code may run on battery powered laptops and in general it doesn't seem clean to me (but I may be wrong on the "clean" statement). The code is also a simplification of the real code.

So this is my situation, any ideas or am I missing something?

Also: another thing I noticed is that game engines like Unreal, Unity3d etc manage to get more than 66fps (so sleeping/waiting less than 15ms) while at the same time not consuming an entire core if it's not needed. Of course their core is mainly written in C++ and not C#, but how do they do that?

Many thanks

Community
  • 1
  • 1
MastErAldo
  • 634
  • 3
  • 12
  • 29
  • Are you writing a game? If not, then comparing your scenario to game engines isn't useful. A 3d game's main bottleneck is waiting on the video card; they do a bit of housekeeping, then hand a ton of data off to the video card, and wait for a frame buffer to be available so it can do that all again. The CPU is generally not close to full utilization, especially on modern hardware. – Peter Duniho Nov 19 '15 at 07:49
  • As far as your question goes, it's pretty broad and hard to understand. What are these tasks that you require be executed at 1000Hz? Can they all really complete in under 1ms? Why 1000Hz? What's wrong with using the CPU? A spin wait is about all you can do to get _timing_ at that high a resolution on a non-real-time OS, and of course that will not release the CPU. There are a lot of seemingly irrelevant details in the question, and yet at the same time, not enough of the important details. – Peter Duniho Nov 19 '15 at 07:49
  • It's part of a thesis, and yes, the whole application can be seen as a game engine, even if not a standard one. Actually that update loop is the scheduler of every task, tasks have their scheduling time, I mean: one event can be scheduled 60 times per second and another can be scheduled 100. I said up to 1000 because I thought 1000 gives enough granularity for every task that and yes, since a task can be as trivial as setting a variable there are tasks that Caan be completed in less than a millisecond. The point is: 1000 may be too high, but 66 is certainly too low – MastErAldo Nov 19 '15 at 13:17
  • Windows already has a scheduler. It's not a real-time scheduler and cannot provide 1 ms resolution. It does have multimedia timers, which you _might_ be able to use in your scenario. Barring that, it seems to me you are really talking about writing a whole new OS; or maybe modifying an open-source one (e.g. Linux) so that it has the higher-resolution thread scheduling you want. – Peter Duniho Nov 19 '15 at 17:11
  • Multimedia timers are what I also found a couple hours ago and this C# wrapper: http://www.codeproject.com/Articles/5501/The-Multimedia-Timer-for-the-NET-Framework seems to provide what I need. No, writing a new OS is far more than what I need,I just need a loop that executes tasks with a fine granularity, what tasks depends on the user that will use this framework. I realize and apologise about my request being a bit vague,but explaining all my thesis and decisions behind it would require too much time I'm afraid. Once finished I would be happy to post a reference to it to explain its details – MastErAldo Nov 19 '15 at 17:31
  • If multimedia timers do address your problem, please vote yourself to close this question as a duplicate of [What is the impact of Thread.Sleep(1) in C#?](http://stackoverflow.com/q/508208). There is no need to post a reference to your completed thesis here; Stack Overflow questions are supposed to be focused, distilled down to their minimum, specific problem and it seems that with your clarifications, we have determined your question has already been answered on Stack Overflow. Thanks. – Peter Duniho Nov 19 '15 at 18:03

0 Answers0