views:

339

answers:

9

Hello,

is there a way to execute a function that is called thousand of times only once ? I have a function that adds items in a container of sort, and there is code in there, that updates lists and other windows (GUI staff). So, if i have to add a million items (the number of which is impossible to tell, anyone could call the function from anywhere), the GUI update mechanism will be called as many as times... Is there a way to tell appart continuous function execution (and ignore it) from discontinuous ? Is there a safe way to execute the update mechanism only the last time the add-item function is called, within a time interval ?

Thank you.

+5  A: 

You could put a static bool that, if true, exit from the function.

klez
Technically, the function would still be executed - only that it would return earlier :)
Daniel Daranas
Daniel: if the function is local (same file) and the compiler is smart, it won't.
SF.
The OP's code is broken, but this is the best solution in the general case. +1.
Billy ONeal
-1: I don't think the OP wants the code never to be executed again after the first call, but only to merge successive calls.
RaphaelSP
It's a terrible idea, as you do not couple it with some RAII feature to ensure that the `bool` is reset at some point... if anything happens that let that `bool` at `true`, your only choice is to kill the program and try anew, urk.
Matthieu M.
+1  A: 

Probably better to make your update trigger manually.

SLC
A: 

If you're ok with a timer and using the Win32 API, you could use the SetTimer method to start a timer to trigger in the future each time the function is called. The behavior of SetTimer is that if you call it again with the same TimerID before the first call has gone off, then the timer gets reset. So you can call SetTimer each time the function is called and you'd be guaranteed the timer would only trigger "n" milliseconds after the last call.

  UINT_PTR timerID = SetTimer(NULL, someUniqueID, 1000, yourCallback);

Just remember to call KillTimer afterwards to cleanup.

MSDN for SetTimer

cpalmer
Solution must be crossplatform. Thank you.
Roesone
A: 

You need to aggregate the updates to the container over a period of time and then perform your update actions after this time period (easier said than done!). It's important that you are clear which actions are appropriate to aggregate together and which aren't.

The real point is that if you are worried about performance in an area then that is the area that you should concentrate your efforts on e.g. if you are performing UI update actions at a frequency much higher than your UI display update frequency (or higher than you practically need) then that is the code that should aggregate it's update over the time interval.

You also need to ensure that you don't leave data structures stale so that the last notification will be acted upon within a timely fashion, even if the next update doesn't happen for a long time.

TheJuice
A: 
// Not quite real code.
bool function_impl(params)
{
    // Do the work.
    return true;
}

void function(params)
{
    static bool temp(function_impl(params));
}
Mark B
A: 

The best solution (IMHO) is the one that .NET uses for most of it's controls:

Create some sort of a "SuspendLayout" method that sets a boolean and only update the GUI if it is not set. Add a "ResumeLayout" that then updates the GUI.

This way if the user of your class only updates a single item he doesn't have to change anything and if he updates several times he can say so and your class doesn't have to worry about it.

This also allows you to optimize for batch updates if neccessary, i.e. pre-allocating more space in the list. You could also add an override to the SuspendLayout that indicates the number of items that will be added (SuspendLayout(int forNumberOfItems)) so you can initialize the list with the correct amount of space.

dbemerlin
+11  A: 

Roesone, your code is broken. It is resisting your attempts to write it because it knows it is wrong. You can probably find some grungy hack that will emit the behavior you desire -- for now. But that solution will be a hack; brittle, prone to errors and difficult to maintain. And especially vulnerable to ripple effects. As soon as you make one small change in your code somewhere in something that remotely touches this functionality, the grungy hack will break and you'll be worse off than you are now.

No, the solution here isn't to find a hack that will work. The solution is to fix your code. Fundamentally this means writing two functions. One that inserts the data in to the container, and another completely seperate function that renders that data to the screen. You can then engineer mechanisms specifically for those methods. For instance, you might update the screen ten times per second, while permitting inserts with no restrictions.

Do yourself, your coworkers and the free world a favor and fix your broken code.

John Dibling
OK, let's assume for now, that the code that adds item to the container just "marks" something for update, which is very fast (to mark). And the GUI, could somehow check if it has "marked" entities, and take actions accordingly. Would you agree with something like that ?
Roesone
@Roesone: Yes, this is a very common pattern. When updates come in, "mark the view dirty" and then periodically update the screen when the view is dirty. Good solution
John Dibling
@John, let's assume people don't like lazy updates, and that we have to update the screen at some time, then i still need a mechanism to fire updates at some time intervals, am i correct ? Is this a safe procedure ? I don't think it is.
Roesone
There are essentially 2 ways to go about it, or use polling at certain time intervals as john dibling says (which is very common for certain GUI updates. for example drawing of a graph based on real time data input), or use some kind of interrupt initiated from outside the gui code, as other ppl are suggesting.
Emile Vrijdags
@Roesone: Typically GUIs are updated on a timer. You can select a timer interval that makes sense to you, be that twice a second, 60 times per second, etc. But it also makes sense to provide a mechanism to trigger an immediate GUI refresh. In Windows, this mechanism usually revolves around using PostMessage() (note, not SendMessage(), which blocks)
John Dibling
@Roesone: When you say "people don't like lazy updates" do you mean updates on a timer? If so, I say that people don't need to know you are updating on a timer. I work on realtime financial systems. My users are ultra-sensitive to even negligible display lag, and I can tell you that as far as they know, our updates are instant. A human cannot tell the difference between 10-20 updates per second and one update every time some stock ticks.
John Dibling
@Roesone: As far as the instant-update-trigger mechanism being safe, it can be safe so long as you keep the GUI rendering seperate from the container updating mechanism. A good way to do this is by sending some kind of message or signal to trigger the instant update, but not block on the messae. In other words, send the message but don't wait for a response. Dont wait for the GUI to update. It will happen soon.
John Dibling
+2  A: 

What if you had a way to turn off the "redraw" ( GUI update ) for those situations where you want to add many items?

// add one item:
window.add_item()

// add many items:
window.set_redraw(false)
window.add_many_items()
window.set_redraw(true)

Then your add_item function simply checks the flag before updating the GUI. The simple case of adding one item remains unchanged.

Nick Perkins
A: 

It depends on the framework you use for GUI.

Basically, it boils down to have the following pseudo code :

bool g_isValueModified = false ;
Value g_value ;

void setValue(Value value)
{
   g_value = value ;
   g_isValueModified = true ;
}

void updateValueOnGUI()
{
   if(g_isValueModified)
   {
      g_isValueModified = false ;

      // put here the code to set the value in the GUI widget
   }
}

The method setValue should be called as much as necessary, while the method updateValueOnGUI should be callled, say, once every 10 or 100ms.

To achieve this asynchronous behaviour, either:

  • if on raw Win32, use a Win32 timer to call your WinProc
  • on advanced GUI framework, use a timer
  • or, on advanced GUI framework, use two separate threads, one for code execution (using the set method) and one for GUI execution (executing the update), making sure g_value and g_isValueModified are written/read in multithread-safe fashion (i.e. locks, critical sections, etc.).
paercebal