From: Alex Fenton Date: 2008-07-24T17:24:28+09:00 Subject: Re: Of GUIs threads and scheduling woes Glen Holcomb wrote: > I have a small GUI app that I have written the purposes for it's creation > are two-fold and irrelevant. Here is my problem: > > I have two threads aside from the main thread. One that wakes machines at > scheduled times and another that shuts them down at scheduled times. > Unfortunately Ruby's scheduler seems to care less when a thread actually > wakes up as long as it doesn't wake up early. Sometimes I have a five > minute (wall time) gap between when the thread should wake and when it > actually does. > > The observed behavior seems to be magnified/caused by minimizing the > application. Does anyone have any suggestions that could lead to a more > responsive app? 5+ minutes late wouldn't matter so much if it didn't cause > the thread to miss an event scheduled a minute or two after the one that was > late. I suppose I could re-structure my code and may have to. I was just > hoping that there is a way to get tolerable responsiveness out of a thread. Most of the GUI libraries for Ruby are based on C/C++ and while a GUI app is running spend most of the time in an "event loop" - a bit of native code which waits for user actions. As I understand it, ruby's thread scheduler won't switch thread context whilst native extension code - eg the event loop - is executing. So non-GUI ruby (green) threads can get starved of execution time. There are two possible solutions to this, the exact implementation of which will depend on the toolkit. Both depend on using the timing/regular event facilities provided by GUI toolkits, which will be respected by the event loop - I've seen discussion relating to different libraries. I'll use Wx as an example. One is to regularly schedule time for the non-GUI threads, using Ruby's Thread.pass. In wxRuby: Wx::Timer.every(50) { Thread.pass } This sets a Timer which will wake and run the subordinate threads every 50ms. The other way is to dispense with Ruby's thread's altogether and just use a timer. This may be more suitable for your use case: Wx::Timer.after(5000) { DO SHUTDOWN ACTION... } hth alex