Jump to content
  • Advertisement
Sign in to follow this  
mb108

Timer class

This topic is 3667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Happy Thanksgiving! Design Question: I have an EventTimer class that stores a priority queue of TimedEvent objects sorted by the time they are scheduled to be triggered. It spawns a thread in the constructor that sends the events off to the main handler, sleeping in between scheduled events. I originally intended this class to be a monolithic, "All your timers are belong to me", sort of object. And it is. But there's some problems with it. Recurring events will go on for the life of the timer, and if an Event is added while the monster is sleeping, it will be queued but ignored until the thread wakes. (imagine it's sleeping for the next event in 5s, and you add something that's supposed to go off in 1s). So. Is there any way to salvage this beast? My thoughts: Yes, but it's complicated. Recurring events could be issued IDs that can be used to cancel them later on. I could do some sort of fancy blocking scheme where the first thread blocks on a conditional, a 2nd thread sleeps until the next known event, and then either the addition of a 'sooner' TimedEvent -or- the 2nd thread waking will unblock the 1st thread. In short, NO. I will probably strip out the queue, and have a timer object track 1 event in 1 thread. Each timer will be local, be destroyed with it's owner, and the lifespan of recurring events will be naturally limited. No conflicts over sleeping threads. Your thoughts: Would love to hear them. Source is GPLv3 and WIP, check it out here if you like. Event.h Event.cpp (scroll to the bottom to find the EventTimer class) Cheers!

Share this post


Link to post
Share on other sites
Advertisement
That actually had not occurred to me, and is a very simple solution. In the purely academic sense, it is a form of busy-waiting (albeit a very slow kind of busy), but I think practically speaking it would be fine.

Another option would be to switch from the feature-scarce GLFW thread functions to boost::thread. I would get thread::interrupt(), and also some shared locking stuff that could simplify other parts of the code.

The createTimer function would interrupt the timer thread if it's sleeping on an event that happens later than the new event. The handling loop would have to catch a boost::thread_interrupted exception and act accordingly.

Share this post


Link to post
Share on other sites
Or, you could wait on a condition variable, specifying a timeout equal to the closest scheduled event in the future (which may be 1 second, or 5 seconds, or whatever).
When another thread adds an event, it signals the condition variable, so you can recalculate the next closest event, possibly do something, and go to sleep again.

Actually a semaphore would do too for this application... but unluckily, GLFW doesn't have semaphores, so you'll need a GLFWCond.

Share this post


Link to post
Share on other sites
You might not want to mess with threads if you can help it. The solution becomes *much* easier with respect to many other issues, and also much more deterministic:
while (running) {
time t = now();
handleInput();
handleExpiredTimers(t);
updateLogic(t);
render();
};
In handleExpiredTimers you check, duh, which timers expired and notify interested parties.

This makes timing somewhat more predictable as well, since times are no longer bound to system time but actual logic time.

Always remember that threads are non-deterministic. They may be given processing time, or they might not. They make wake when desired, or they might not. This becomes a problem as soon as the CPU is overloaded and threads start to compete for resources. Not to mention that threaded timer invocations require you to lock the state.

And never use Sleep() for anything that resembles a timer based on real time. Sleeping means to sleep at least that long, but it may sleep forever or for 3 hours. If you need a periodic event that needs to do something every once in a while, the Sleep is ok. But emphasis is on "once in a while".

Share this post


Link to post
Share on other sites
samoth, this is basically the solution that was winning out in my mind. I will probably switch to boost::thread at some point, but I just double checked and boost doesn't have a semaphore either. So it would still be a similar situation.

Antheus, point well taken. The EventHandler class above it is *pervasively* multithreaded, handing off tasks to a thread pool, so I have already perpetrated many crimes against determinism. However, that class also provides a no-thread/stepping solution, so I should probably do something similar for EventTimer.

This has been a learning and portfolio-building project, so some of the design is more rooted in curiosity that it is in practicality. \o/

Thanks for the replies.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!