-2

I have a function that is being used to update some information displayed on a GUI. The information should only be displayed for a short length of time (about 10 seconds).

The function being used to set what is displayed on the GUI is called repeatedly, and what is displayed is dependent on conditions within that function.

The issue that I'm having at the moment, is that there is some information being displayed that needs to change depending on how long it has been displayed for.

I tried creating a variable that was set to the system time at the beginning of the function, and then later in the function, had a condition that would change the value of the variable if the current system time was greater than the original system time + 10 seconds.

However, the problem with that was that since the function is being called repeatedly, the original system time is updated with every call/ iteration.

I found the following quesion on SO: How to run code inside a loop only once without external flag? and tried to implement what was suggested in the answer by Angew, so that the variable holding the original system time would only be set once within the loop. My code currently looks like this:

struct rnOnce{
    template <typename T>
    runOnce(T &&f){ f(); }
};
...

void updateHeader(){
    ...
    static runOnce a([](){
        timeWarningStarted = SimulationTime::Instance()->getSimulationTime();
    });
...

But when I run my program, and attach to process in debug, the call to static runOnce a([](){... }); appears to be skipped- none of the breakpoints I've put on these lines are ever hit, even though the breakpoints on the lines just before and just after are.

Can anyone explain to me why this is? What am I doing wrong here?

EDIT

The desired behviour is that the timeWarningStarted variable is only given a value once, despite the fact that it is being set inside a function that is called several times. It is a global variable- and the function that is setting its value will be continuously called as that is the one that's used to update what is displayed on the GUI.

Effectively, I want timeWarnigStarted to be set to the current system time the first time that this code is executed, and then to retain its value for the duration of time that the program is running.

Before changing my code to what it is above, I had something similar to:

void updateHeader(){
    ...
    timeWaringtarted = SimulationTime::Instance()->getSimulationTime();
    ...
}

But this was in issue because timeWarningStarted was being given the current system time every time this function was run (i.e. it was continuously being updated). So, later in the same function, when I wanted to check whether the warning had been displayed for 10 seconds, and if so, to stop it from being displayed, I was doing something like:

void updateHeader(){
    ...
    timeWarningStarted = SimulationTime::Instance()->getSimulationTime();
    ...
    currentSimulationTime = SimulationTime::Instance()->getSimulationTime();
    if(currentSimulationTime <= (timeWarningStarted + 10)){
        warningMessage = "";
    }
    ...
}

But obviously, since both timeWarningStarted & currentSimulationTime will be given a new value every time the above code is run, they will have too close a value because they will be set at almost exactly the same time.

So, by setting timeWarningStarted inside runOnce, I was hoping that timeWarningStarted would only be given a value the first time that this code was run, and would retain that value for the duration of the simulation, but it appears that this section of code is now never run...

static runOnce a([](){
    timeReplyFailWarningStarted = SESL::SimulationTime::Instance()->getSimulationTime(); // = 0;
});
Community
  • 1
  • 1
Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118
  • The RunOnce solution is over-engineered, you can just do `static const auto once = (timeWarningStarted = blahblah);` – Jonathan Wakely Jul 06 '15 at 11:10
  • 1
    Questions seeking debugging help ("**why isn't this code working?**") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it **in the question itself**. Questions without **a clear problem statement** are not useful to other readers. See: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). – Jonathan Wakely Jul 06 '15 at 11:14
  • http://en.cppreference.com/w/cpp/thread/call_once ? – Daniel Jour Jul 06 '15 at 11:49
  • I described the desired behaviour a bit more fully. – Noble-Surfer Jul 06 '15 at 12:17

1 Answers1

0

To set timeWarningStarted the first time updateHeader() is called (not after, and not before), a simple technique is

void updateHeader() {
    ...
    static bool warningHasStarted = false;
    if (!warningHasStarted) {
        timeWarningStarted = SimulationTime::Instance()->getSimulationTime();
        warningHasStarted = true;
    }
    ...
}
David K
  • 3,147
  • 2
  • 13
  • 19
  • This answer assumes the warning should be displayed for a fixed time near the start of the execution of the program and then never shown again as long as the program is running. If you want something different then additional logic will be needed to support it. – David K Jul 06 '15 at 12:21
  • Hey, thanks for your answer. This is the first thing I tried... Unfortunately it doesn't work- because the `updateHeader()` function is called repeatedly, each time it is called, it runs through in its entirety- so doing what you've suggested, `warningHasStarted` will be set to false with every call... so although it will be set to true inside the `if`, once the rest of the code inside the function has run, it will go back to the start and set `warningHasStarted` to false again- meaning that the code inside the `if` will then be run a second time... – Noble-Surfer Jul 06 '15 at 12:24
  • The `static` keyword prevents the initialization of `warningHasStarted` from occurring more than once. I have used this technique in the past. Note that the `static` keyword is absolutely necessary; the technique will not work if you leave that out. – David K Jul 06 '15 at 12:29
  • Ok, so I've tried what you suggested, but the issue I'm now having is that `timeWarningHasStarted` is given the same value is being given the same value as the time variable I'm using later in the function (`currentSimuationTime`), which although I am setting using the same `getSimulationTime()` function, because that statemen will be executed after the first one, I would expect it to have a different value. However, it appears that this second use of `getSimulationTime()` is occurring too soon after the first one for there to be a significant difference beween the time values returned... – Noble-Surfer Jul 06 '15 at 13:45
  • So, wait, you're saying that `currentSimulationTime = SimulationTime::Instance()->getSimulationTime();` produces the same value of `currentSimulationTime` every time you execute it, in every call to `updateHeader()`? Eventually, _sometime_ during execution of the program, you should see a different value assigned to `currentSimulationTime`. If not, that's your problem: your program is not advancing the "simulation" time. – David K Jul 06 '15 at 14:26
  • No, the `currentSimulationTime` value is updated every time its set, i.e. with every iteration... but so is `timeWarningHasStarted`, so they have the same value as each other in every iteration (even though those values increase with every iteration). What I need is for `timeWarningHasStarted` to be given a value exactly one time (the first time this code is executed), and to retain that value every time the code is executed... but for `currentSimulationTime` to be given a new value every time the code is executed, so that the difference between these two values will increase every time. – Noble-Surfer Jul 06 '15 at 14:52
  • Eventually then, the value of `currentSimulationTime` will be greater than 10 seconds after the value of `timeWarningHasStarted`, at which point the warning will cease to be displayed. – Noble-Surfer Jul 06 '15 at 14:53
  • I have used this one-shot pattern in my own code and I am fairly sure it does exactly what you asked. If you have implemented it _exactly as shown_ and you still think it does not work, please give specific evidence, such as two different values of `timeWarningHasStarted` that you observed during a single run of the program. And make sure there is _no other_ statement (other than static initialization) assigning anything to `timeWarningHasStarted`; in fact there's no reason for this variable to be defined outside this function; it could be defined `static` within the function. – David K Jul 06 '15 at 20:15