I would recommend that in your code, you maintain counters that get incremented. The counters can be static
class members or globals. If you use a class to define your counter, you can have the constructor register your counter with a single repository along with a name. Then, you can query and reset your counters by consulting the repository.
struct Counter { unsigned long c_; unsigned long operator++ () { return ++c_; } operator unsigned long () const { return c_; } void reset () { unsigned long c = c_; ATOMIC_DECREMENT(c_, c); } Counter (std::string name);};struct CounterAtomic : public Counter { unsigned long operator++ () { return ATOMIC_INCREMENT(c_, 1); } CounterAtomic (std::string name) : Counter(name) {}};
ATOMIC_INCREMENT
would be a platform specific mechanism to increment the counter atomically. GCC provides a built-in __sync_add_and_fetch
for this purpose. ATOMIC_DECREMENT
is similar, with GCC built-in __sync_sub_and_fetch
.
struct CounterRepository { typedef std::map<std::string, Counter *> MapType; mutable Mutex lock_; MapType map_; void add (std::string n, Counter &c) { ScopedLock<Mutex> sl(lock_); if (map_.find(n) != map_.end()) throw n; map_[n] = &c; } Counter & get (std::string n) const { ScopedLock<Mutex> sl(lock_); MapType::const_iterator i = map_.find(n); if (i == map_.end()) throw n; return *(i->second); }};CounterRepository counterRepository;Counter::Counter (std::string name) { counterRepository.add(name, *this);}
If you know the same counter will be incremented by more than one thread, then use CounterAtomic
. For counters that are specific to a thread, just use Counter
.