我有一个产生各种类型线程的函数,其中一个线程类型需要每隔x秒生成一次。我现在有这样的话:
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;
}
}
}
但我想把它改成:
bool isTime()
{
static Time t = now();
if( t >= now() )
{
t = now() + offset;
return true;
}
return false;
}
void spawner()
{
while( 1 )
{
if( isTime() )
launchthread();
}
}
我认为第二种方式更整洁,但我通常避免静态,就像我避免全局数据一样;有人对不同的风格有什么想法吗?
答案 0 :(得分:4)
除了我在问题评论中提到的问题,你应该避免像瘟疫一样聪明的伎俩。第一种形式(修复bug之后)更清晰,更容易理解。第二种形式,OTOH,给人的印象是,t
的分配和t >= now()
的分配紧接着发生在彼此之后,他们在意识到它的静态,然后必须试图让算法第二次。
此外,您永远不能重置第二个功能或从多个线程使用它。
答案 1 :(得分:3)
static Time t
方法的一个缺点是静态变量的函数通常不是可重入的(因此不是线程安全的) - 这对您来说可能是也可能不是问题。
想象一下,如果您有两个独立spawner
并使用static Time t
会发生什么。
如果你更喜欢第二种形式,你可以实现非常相似的东西,但不使用静态:
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();
}
}
答案 2 :(得分:2)
“第二种方式”具有更易于阅读的spawner
功能。但是通过使用例如它可以使其同样可读。成员变量i.s.o.一个全球化的国家。
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
}
};
有了这样的课程,你可以创建一些“Spawners”,而不必费心去保护你的全球状态:
Spawner very_often( .5 );
very_often.keep_spawning();
答案 3 :(得分:1)
我建议使用第一个版本,因为它更容易测试。输入和输出清晰可见,您可以通过将有趣的时间值输入其中来很好地执行边界测试。如果您有引用全局和/或静态数据的代码,则无法执行此操作。
答案 4 :(得分:1)
如果你有一个提供线程的库,它也应该提供定时器。例如,WinAPI提供每X秒调用给定函数的功能。这可能是最好的解决方案。
答案 5 :(得分:0)
static Time t
方法隐藏了其余代码的时间。如果这是你的意图(你不需要在其他地方使用全局时间而变量t
只是为了决定是否产生线程),那么静态方法似乎更适合我。
但是,如果您的程序是例如模拟,当前时间对程序的所有部分都至关重要,我个人会不去隐藏时间变量,并像第一部分一样实现isTime
代码。