2013-05-09 43 views
1

摘要:我想看看我是否可以重構具有規律,以使其更易於更新和維護一些C++代碼。重構規則的C++代碼模式

詳細

我有一個創建線程本地計數器來跟蹤統計的程序執行過程中的一些代碼。目前,當統計信息添加到源代碼中時,需要更新5件事情:計數器線程本地聲明,計數器總計聲明,重置線程計數器的函數,將線程計數器添加到總數的函數,和打印功能。

的代碼是類似以下內容:

// Adding a statistic named 'counter' 

// Declaration of counter 
__thread int counter = 0; 
int total_counter = 0; 

// In reset function 
counter = 0; 

// In add function 
total_counter += counter; 

// In print function 
printf("counter value is: %d\n", total_counter); 

我可以看到一個宏可以在櫃檯做類似的聲明創建:

#define STAT(name) __thread int name; \ 
        int total_##name; 

但我沒有想到如何將其擴展到更新addreset功能。理想情況下,我想輸入諸如STAT(counter)之類的東西,並具有用於管理統計信息的所有聲明和功能。

編輯

我已經在代碼更新的統計數據宏。這樣的東西,如STAT_INC(counter)會增加本地計數器值。然後當線程完成執行時,線程本地值將被添加到整體總數中。所以每個統計的名字都很重要,這就是爲什麼一個數組不適合我的原因。因爲真正的計數器名稱是cache_hit,比counter[2]更有意義,我不想失去爲創建的統計信息指定任意名稱的能力。只是爲了簡化我在聲明統計信息時必須編寫的代碼量。

+2

使用數組(或向量,管他呢)。 – 2013-05-09 18:55:26

回答

1

這使得或多或少你在你的問題封裝在一個模板類描述了:

enum StatNames { 
    STAT_rx_bytes, 
    STAT_tx_bytes, 
    //..., 
}; 

template <StatNames SN> 
class Stat { 
    static const char *name_; 
    static __thread int x_; 
    static int total_; 

public: 
    Stat(const char *name) { name_ = name; } 
    static void reset() { x_ = 0; } 
    static void add() { total_ += x_; } 
    static void print() { 
     std::cout << name_ << " value is: " << total_ << "\n"; 
    } 
    static int & x() { return x_; } 
    static int total() { return total_; } 
}; 

template <StatNames SN> const char * Stat<SN>::name_; 
template <StatNames SN> __thread int Stat<SN>::x_; 
template <StatNames SN> int Stat<SN>::total_; 

#define STAT(name) Stat<STAT_##name> name(#name) 

然後,您可以編寫代碼如下所示:

STAT(rx_bytes); 

void * test (void *) 
{ 
    rx_bytes.x() += 4; 
    rx_bytes.add(); 
    std::cout << pthread_self() << ": " << rx_bytes.x() << "\n"; 
    return 0; 
} 

int main() 
{ 
    pthread_t t[2]; 
    pthread_create(&t[0], 0, test, 0); 
    pthread_create(&t[1], 0, test, 0); 
    pthread_join(t[0], 0); 
    pthread_join(t[1], 0); 
    rx_bytes.print(); 
} 
1

(沒人接7分鐘後...我得到的禮物!)

所以基本上你不想五個獨立的命名變量。您可以使用數組或向量:

int counters[5]; 

那麼它很容易更新某個計數器:與所有其他變量

class Counter { 
    int counters[5]; 
    void update_nth(int n) 
    { 
     counters[n]++; 
    } 
}; 

同樣。

+0

我不認爲這正是我正在尋找的。在我的問題中,我可能沒有解釋得很好。我希望能夠用'foo'或'bar'等任意名稱來聲明計數器。然後我有一些函數在某些時候已經被調用來合計線程本地'foo'值。我可能不明白你的答案,但我不認爲它允許我用任意名稱定義新變量(這對於讓代碼自我記錄很重要)。 – 2013-05-09 19:31:55

+0

@Gabriel如果你真的想重構一些代碼,那麼你就不能有名字**和**自動/統一更新(除非你把所有的東西都封裝在一個'switch-case'中,但這是一個徹底的失敗) – 2013-05-09 19:33:26

+0

感謝您的評論和答覆。即使我不能比我現在做得更好,知道我不會錯過簡單的東西是有用的。 – 2013-05-09 19:42:06

1

跟進H2CO3的回答,有一個常見的成語,看起來像這樣:

enum CounterEnums { 
    MyFirstCounter, 
    MySecondCounter, 
    // ... add new counter names here ... 
    NumCounters 
}; 
class Counter { 
    int counters[NumCounters]; 
public: 
    void update(int n) { counters[n]++; } 
}; 

現在,你可以輕鬆地添加另一個櫃檯,只是把它NumCounters之前。現在,你可以宣佈你的情況下,是這樣的:

Counter totals; // global 
boost::thread_specific_pointer<Counter> counters; // per-thread 

,並使用

counters->update(MyFirstCounter); 

(你還需要一些方法來更新totals和零您的每個線程的櫃檯,但我將......留給讀者作爲練習)。