Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site













SourceForge.net Logo

About modal loops and periodic timer events

 

In this article we try to explain what is wrong with this piece of code:

 

#include <CtrlLib/CtrlLib.h>

 

class LOOP : public TopWindow {

public:

    typedef LOOP CLASSNAME;

    LOOP();

    void f1();

};

 

 

LOOP::LOOP()

{

    SetTimeCallback(-1000, THISBACK(f1));

}

void LOOP::f1()

{

    PromptOK("prompt!");

}

 

GUI_APP_MAIN

{

    LOOP().Run();

}

 

The trouble is that the PromptOK box gets opened over and over again, so very soon you start running out of Windows resources (window handles). This slows down the repaint. Of course if you click one of the boxes, many others are already stacked below it so that you're never able to close them all.

 

Using a periodic timer is a tricky thing; remember that it keeps running all the time, even as you feel from the GUI viewpoint that it's been blocked by something. Actually, this 'heartbeat' lies at the very core of the Ctrl system, so it just runs whenever the event processing is allowed to take place. Also remember that the TimeCallback dispatcher routine is fully reentrant in the sense that it can continue sending other timer messages even until you return from the function called by it.

 

So the flowchart of your application basically breaks down to the following. For clarity, a summary of the allocated stack frames is written below each phase to help you get a better understanding of the issue.

 

Entry into WinMain

stack [WinMain]

install timer ticking each 1 second

stack: [WinMain] [LOOP::LOOP]

run event loop in the LOOP window

stack: [WinMain] [LOOP::Run]

after 1 second: f1 gets called

stack: [WinMain] [TopWindow::Run] [timer] [LOOP::f1]

PromptOK gets displayed and its modal loop run

stack: [WinMain] [TopWindow::Run] [timer] [LOOP::f1] [PromptOK::Run]

after another second: f1 gets called again, but on a higher stack frame

stack: [WinMain] [TopWindow::Run] [timer] [LOOP::f1] [PromptOK::Run] [timer] [LOOP::f1]

another PromptOK gets displayed ands its modal loop run

stack: [WinMain] [TopWindow::Run] [timer] [LOOP::f1] [PromptOK::Run] [timer] [LOOP::f1] [PromptOK::Run]

after another 1 second: f1 gets called a third time, continuing a theoretically infinite recursion

 

Now, if you had a simple infinite recursion in a computational part of your application, it is quite likely that you would run out of stack very soon, so typically after a few seconds the application crashes on stack overflow (remember that, in Windows, this is a little tricky, because if you're not running the application in the debugger, the stack overflow usually causes the application to immediately close quietly without the normal annoying 'Fatal application error' box. I believe this is so because once the stack gets completely exhausted, Windows don't dare run any other message loop on top of it).

 

However, your situation is a little different. According to the formulation of your application, the stack grows relatively slowly - just about a few hundred bytes a second, I guess, which in view of the default 1 MB application stack limit it not that much, so your application can (from the stack point of view) run at least a quarter of an hour, maybe more. However, during that quarter hour the application would allocate about 1000 Prompt boxes, which might not be strictly beyond Windows capabilities, but at least it is sure to slow things down a lot. By the way, by pressing Ctrl+F4 and holding it for autorepeat you should be able to close all the prompt boxes and the application as well, because the autorepeat should be faster that the prompt creation interval and by holding it down for a while you should relatively quickly eat the abundant stack frames (until finally you close the last PromptOK box and then the LOOP window itself, after which your application exits the LOOP::Run modal loop and exits WinMain).

 

I hope I haven't wrought more havoc in your view of the above matter than necessary. Keep in mind that very many things in a Windowing system are reentrant and it is not at all impossible, and under circumstances it is in fact quite likely, that the same function or method gets called from various stack frames, sometimes even multiple times at once (not in the multithreaded-sense, but recursively from a subfunction called by the outer execution of the method). To be quite honest, bugs linked to such recursions are sometimes worst to catch, especially when they are connected with destruction of an object. (Imagine a situation, in which the destructor of a Ctrl-based object performs some cleanup and during its processing the callback mechanisms linked to its member objects, like dialog controls, transfer control back to this half-destructed object. By the way, this is perhaps the main reason for the Shutdown mechanism in Ctrl's.) Most critical spots in the CtrlCore library ifself are protected by various means against such situations, but this doesn't mean that such a recursion cannot crash your application.

 

Last edit by cxl on 12/02/2017. Do you want to contribute?. T++