What I would like to know about the code below, is: Are the use of try catch blocks around method calls good practice. What are the follies in the code below?
#ifndef TIMER_H
#define TIMER_H
#include <boost/bind/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/function.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <stdint.h>
#include <iostream>
#include <vector>
template <uint32_t tMilliSeconds>
class Timer {
private:
static Timer *_instance;
uint32_t mMilliSeconds;
boost::mutex mListMutex;
boost::thread mTimerThread;
std::vector<boost::function<void()> > mHandlerList;
Timer();
Timer(const Timer &other);
Timer &operator=(const Timer &other);
void Run();
public:
~Timer();
static boost::shared_ptr<Timer<tMilliSeconds> > Instance();
void AddHandler(boost::function<void()> tmpBoostFunction);
};
template <uint32_t tMilliSeconds>
Timer<tMilliSeconds>::Timer() :
mListMutex() {
mMilliSeconds = tMilliSeconds;
mTimerThread = boost::thread(
boost::bind(&Timer<tMilliSeconds>::Run, this));
}
template <uint32_t tMilliSeconds>
Timer<tMilliSeconds>::~Timer() {
mListMutex.lock();
try {
mTimerThread.detach();
} catch (...) {
mListMutex.unlock();
}
mListMutex.unlock();
}
template <uint32_t tMilliSeconds>
boost::shared_ptr<Timer<tMilliSeconds> >
Timer<tMilliSeconds>::Instance() {
if (!_instance) {
_instance = new Timer<tMilliSeconds>();
}
return boost::shared_ptr<Timer<tMilliSeconds> >(_instance);
}
template <uint32_t tMilliSeconds>
void Timer<tMilliSeconds>::Run() {
while(true) {
boost::this_thread::sleep(
boost::posix_time::milliseconds(mMilliSeconds));
mListMutex.lock();
for (std::vector<boost::function<void()> >::iterator vect_it =
mHandlerList.begin(); vect_it != mHandlerList.end();
++vect_it) {
try {
(*vect_it)();
} catch (...) {
mListMutex.unlock();
}
}
mListMutex.unlock();
}
}
template <uint32_t tMilliSeconds>
void Timer<tMilliSeconds>::AddHandler(
boost::function<void()> tmpBoostFunction) {
mListMutex.lock();
try {
mHandlerList.push_back(tmpBoostFunction);
} catch (...) {
mListMutex.unlock();
}
mListMutex.unlock();
}
#endif // TIMER_H
Since you’re using boost, I would look into using a mutex in conjuction with a
boost::scoped_lock, so that when thescoped_lockobject goes out of scope, the mutex is “automagically” unlocked via its destructor call. You then won’t need to worry about interleaving mutex unlocking with yourtryandcatchblocks, since the unwinding of the stack via an exception will release the lock on the mutex via thescoped_lockobject.