views:

99

answers:

6

I have a function which spawns various types of threads, one of the thread types needs to be spawned every x seconds. I currently have it like this:

bool isTime( Time t )
{
     return t >= now();
}

void spawner()
{
    Time t = now();
    while( 1 )
    {
         if( isTime( t ) )//is time is called in more than one place in the real function
         {
             //launchthread and recalculation of t only happens once in real function
             launchthread()
             t = now() + offset;
         }
    }
}

but I'm thinking of changing it to:

bool isTime()
{
    static Time t = now();
    if( t >= now() )
    {
         t = now() + offset;
         return true;
    }
    return false;
}

void spawner()
{
     while( 1 )
     {
         if( isTime() )
             launchthread();
     }
}

I think the second way is neater but I generally avoid statics in much the same way I avoid global data; anyone have any thoughts on the different styles?

A: 

The static Time t approach hides the time from the rest of the code. If this is your intent (you do not need to use a global time somewhere else and the variable t is there just to decide whether to spawn threads or not), the static approach seems neater to me.

However, if your program were for example a simulation, where the current time is crucial to all parts of the program, I would personally go for not hiding the time variable, and implement isTime as in the first piece of code.

Michał Trybus
+3  A: 

One drawback of the static Time t approach is functions with static variables are generally not re-entrant (and are therefore not thread safe) - this may or may not be a problem for you.

Imagine what would happen if you had two independent spawners and used a static Time t.

If you like the second form better, you can achieve something very similar, but without using static:

bool isTime(Time &t)
{
    if( t >= now() )
    {
         t = now() + offset;
         return true;
    }
    return false;
}

void spawner()
{
    Time t = now();
    while (1)
    {
     if( isTime(t) )
          launchthread();
    }
}
Suma
Not a problem when looking at time because time would be the same for both threads - but not a problem here anyway
Patrick
Hmm, I'm not sure, the fact that t changes in isTime is not obvious where isTime is called (although the fact that it won't be a const ref would at least suggest it)...
Patrick
If you prefer it to be explicit, you can always change it to pass as a pointer, not reference - the basic idea stays the same.
Suma
+4  A: 

Apart from the problem I cited in the comments to the question, you should avoid clever tricks like the plague. The first form (after fixing the bug) is cleaner and easier to understand. The second form, OTOH, confuses the reader by giving the impression that the assignment to t and the test t >= now() happen immediately after each other, who, on realising that its static, then has to try to grok the algorithm a second time.

Also, you can never reset the second function or use it from multiple threads.

Marcelo Cantos
Someone looking at the isTime function would have to spend a moment working out what is going on, but it is a very simple function so wouldn't take that much time, however someone looking at the more complicated spawner function (which has a lot more going on than shown here) has slightly cleaner code to look at making that easier to grok. 6 of one, half a dozen of the other maybe?
Patrick
It is half-and-half, but since the same complexity is present in both, I would much prefer the version that doesn't use a clever trick and is reentrant, to boot.
Marcelo Cantos
Yep, I think you're right
Patrick
+2  A: 

The 'second way' has an easier to read spawner function. But it can be made equally readable by using e.g. a member variable i.s.o. a global state.

struct Spawner {
    time when_to_wakemeup;
    timediff step;

    Spawner( timediff astep ): when_to_wakemeup(Now()+astep),step(astep){
    }


    // this is the member-function equivalent of your "spawner" function
    void keep_spawning() {

        while(true) {
            while( Now() < when_to_wakemeup ) Wait();
            when_to_wakemeup += step;
            spawn_one();
        }
     }

     void spawn_one() {
        //... whatever you need
     }
  };

With a class like this, you can create a number of "Spawners" and don't have to bother with guarding your global state:

  Spawner very_often( .5 );
  very_often.keep_spawning();
xtofl
The spawner function is a free function (the main loop) in the code. I think creating a class around it just to make this slightly neater would be overkill...
Patrick
@Patrick: it's up to your design goals. In a stand-alone console app, I would choose the free function. In a library I would go for the class version.
xtofl
Absolutely, I +1'd your answer as it may be useful for someone looking at this thread later, just not what I'm looking for right now
Patrick
+1  A: 

I recommend to use the first version since it's more testable. The input and output is clearly visible and you can nicely perform boundary tests by feeding funny Time values into it. This is not possible if you have code which references global and/or static data.

Frerich Raabe
+1  A: 

If you have a library that offers threads, it should also offer timers. The WinAPI for example offers functionality to call a given function every X seconds. This would probably be the best solution.

DeadMG
Can't find them on msdn (for c++), can you add a link and is there a boost equivalent?
Patrick
I don't know if Boost provides an equivalent. http://msdn.microsoft.com/en-us/library/ms686360(v=VS.85).aspx (scroll to bottom for waitable timer reference). You could also check Intel's Thread Building Blocks for similar functionality.
DeadMG