2010-06-03 86 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