摘要:我正在尝试查看是否可以重构一些具有常规模式的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;
但我还没有想到如何扩展它以更新add
和reset
函数。理想情况下,我想键入类似STAT(counter)
的内容,并拥有管理统计数据的所有声明和函数。
修改:
我已经有了用于更新代码中统计信息的宏。像STAT_INC(counter)
这样的东西会增加本地计数器值。然后当线程完成执行时,它的线程局部值被添加到总计中。因此,每个统计信息的名称都很重要,这就是为什么数组不适合我的原因。因为真实的计数器名称是cache_hit
之类的东西,它比counter[2]
更有意义,我不想失去为所创建的统计信息设置任意名称的能力。只是为了简化在声明统计信息时我必须编写的代码量。
答案 0 :(得分:1)
(7分钟后没有人回答......我收到了礼物!)
所以基本上你不需要五个单独的命名变量。您可以使用数组或向量:
int counters[5];
然后更新某个计数器非常容易:
class Counter {
int counters[5];
void update_nth(int n)
{
counters[n]++;
}
};
与所有其他变量类似。
答案 1 :(得分: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
并将你的每线程计数器归零,但我会......将其作为读者的练习。)
答案 2 :(得分: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();
}