2010-06-03 49 views
0

我有一个函数,它产生各种类型的线程,其中一种线程类型需要每隔x秒产生一次。目前,我有这样的:在函数中使用静态变量vs从调用者传递变量

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(); 
    } 
} 

我认为第二个方法是整洁,但我通常避免在静态几乎相同的方式我避免全球数据;任何人对不同的风格有任何想法?

+2

第一种形式有一个错误。你应该在循环之外设置't'。此外,这两种形式都使用一个繁忙的循环,这将完全捆绑CPU。 – 2010-06-03 10:28:29

+0

修正了这个错误,这是简化的伪代码,而不是我实际上在做的事 – Patrick 2010-06-03 10:38:09

+0

自我修正:第二个版本至多启动一个线程,具体取决于第一次和第二次调用now()量子。它需要外部'while(1)...'循环来匹配第一个版本。但我认为帕特里克的观点只是伪码。 – 2010-06-03 11:12:53

回答

4

除了我在评论这个问题提到的问题,您应该避免聪明的技巧,像瘟疫。第一种形式(修复bug后)更清晰,更易于理解。第二种形式OTOH通过给人一种印象,认为t的分配和t >= now()紧接着发生的印象混淆了读者,他们在意识到其静态的时候必须尝试第二次尝试算法。

此外,您不能重置第二个函数或从多个线程使用它。

+0

有人看isTime函数将不得不花费一点时间来研究发生了什么,但它是一个非常简单的函数,所以不会花费那么多时间,然而有人正在看更复杂的spawner函数(它有很多比这里展示的更多)具有稍微更简洁的代码,以便更容易理解。一个6个,另外6个可能? – Patrick 2010-06-03 10:43:38

+1

它是一半的,但由于两者都存在相同的复杂性,所以我更喜欢那些不使用聪明技巧并且可重入的版本来引导。 – 2010-06-03 10:54:14

+0

是的,我认为你是对的 – Patrick 2010-06-03 10:59:05

0

static Time t方法隐藏其余代码的时间。如果这是您的意图(您不需要在其他地方使用全球时间,并且变量t只是为了决定是否产生线程),静态方法似乎更加贴近我。但是,如果你的程序是一个仿真,其中当前时间对程序的所有部分都是至关重要的,那么我会亲自去隐藏时间变量,并且像第一段代码那样实现isTime

3

static Time t方法的一个缺点是静态变量的函数通常不可重入(因此不是线程安全的) - 这对您而言可能是也可能不是问题。

想象一下,如果您有两个独立的spawner s并使用了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(); 
    } 
} 
+0

当看时间不是一个问题,因为两个线程的时间将是相同的 - 但这里不是问题 – Patrick 2010-06-03 10:35:19

+0

嗯,我不确定,isTime的t变化并不明显,其中isTime被称为(虽然它不会是一个常量参数,至少会暗示它)... – Patrick 2010-06-03 10:51:05

+0

如果你喜欢它是明确的,你可以随时改变它作为指针传递,而不是参考 - 基本思想保持不变。 – Suma 2010-06-03 13:17:20

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 
    } 
    }; 

有了这样的一类,你可以创建一个数字“产卵”的,并没有与守卫您的全局状态打扰:

Spawner very_often(.5); 
    very_often.keep_spawning(); 
+0

spawner函数是代码中的一个自由函数(主循环)。我认为围绕它创建一个班只是为了让这个稍微整齐一点就会过度... – Patrick 2010-06-03 11:01:33

+0

@帕特里克:这取决于你的设计目标。在独立的控制台应用程序中,我会选择免费功能。在图书馆,我会去上课。 – xtofl 2010-06-03 11:05:30

+0

当然,我为你的回答+1,因为它可能对稍后看到此线程的人有用,只是不是我正在寻找的 – Patrick 2010-06-03 11:08:54

1

我推荐使用第一个版本以来它更可测试。输入和输出清晰可见,您可以通过向其中输入有趣的时间值来很好地执行边界测试。如果您拥有引用全局和/或静态数据的代码,则这是不可能的。

1

如果你有一个提供线程的库,它也应该提供定时器。例如WinAPI提供了每X秒调用给定函数的功能。这可能是最好的解决方案。

+0

在msdn(for C++)上找不到它们,你可以添加一个链接,并有相当的提升? – Patrick 2010-06-03 12:35:08

+0

我不知道Boost是否提供了相同的功能。 http://msdn.microsoft.com/en-us/library/ms686360(v=VS.85).aspx(滚动到等待定时器参考底部)。您还可以检查英特尔的线程构建模块是否具有类似的功能。 – Puppy 2010-06-03 12:46:58