|
Boost Users : |
Subject: [Boost-users] Adding a thread to a Singleton class
From: Stephen Torri (storri_at_[hidden])
Date: 2010-01-10 17:29:39
I would like to have a logging class, called Trace, that I can off load
the string formatting of logging the status of my program to a separate
thread. Right now my logging class is written as a singleton object.
This code is located within a shared library and used extensively in it
to write tracing information to a file. Right now all the string
formatting occurs on the main thread which degrades performance.
QUESTION #1: I was wondering if the way in which I am attempting to have
a central point for logging information via a Singleton without passing
around a variable is a practical solution to this problem?
I followed the Singleton guideline from Boost cookbook
( http://www.boostcookbook.com/Recipe:/1235044 ) of how to implement my
singleton. I was thinking that I could add a boost::thread to my logging
class, called Trace, and use a queue to pass objects over to be logged.
A boost::condition would be used to signal the boost::thread to wake up
and lock the queue, copy the contents then start writing the string
formatted to a file.
Below is my initial code. I would appreciate comments on the design,
ideas for better designs and suggestions.
Stephen Torri
---------------- SINGLETON class ----------------------------
#ifndef SINGLETON_H
#define SINGELTON_H
#include <boost/utility.hpp>
#include <boost/thread/once.hpp>
#include <boost/scoped_ptr.hpp>
namespace myproject { namespace trace {
template <typename T>
class Singleton : boost::noncopyable
{
public:
static T& Instance()
{
boost::call_once ( init, m_flag );
return *m_obj;
}
static void init ()
{
m_obj.reset ( new T () );
}
protected:
~Singleton(){}
Singleton(){}
private:
static boost::scoped_ptr<T> m_obj;
static boost::once_flag m_flag;
};
} // namespace trace
} // namespace trace
template <typename T> boost::scoped_ptr<T> myproject::trace::Singleton<T>::m_obj ( 0 );
template <typename T> boost::once_flag myproject::trace::Singleton<T>::m_flag = BOOST_ONCE_INIT;
#endif // define SINGELTON_H
---------------- Trace class -----------------------
#ifndef myproject_TRACE_H
#define myproject_TRACE_H
#include <boost/cstdint.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/thread.hpp>
#include <boost/utility.hpp>
#include <vector>
#include "Trace_State.h"
namespace myproject { namespace trace {
//
// Turn Trace into a singleton class that contains a worker thread
// - Wait for data
// - If data exists then process
// - Else wait
// Add method for adding a ITraceable object. This will lock the logging vector, add
// element then signal the boost condition variable
class Trace : public Singleton<Trace> {
friend class Singleton<Trace>;
public:
void add_Trace ( interface::ITraceable::ptr_t trace );
private:
Trace();
// Worker thread functions
void threadMain();
void processTraces();
// Synchronization variables
boost::mutex m_lock;
boost::condition_variable m_condition;
// Data variables
typedef std::vector < interface::ITraceable::ptr_t > QueueType;
QueueType m_queue;
// Thread variables
boost::shared_ptr<boost::thread> m_thread;
volatile bool m_hasWork;
// Logging
Trace_State m_state;
};
} /* namespace trace */
} /* namespace myproject */
#endif /* myproject_TRACE_H */
----------------- Trace Source -----------------------
#include "Trace.h"
#include "myproject/errors/Internal_Exception.h"
#include <boost/bind.hpp>
namespace myproject { namespace trace {
Trace::Trace ()
: m_hasWork ( true ),
m_state ( "Trace", "Trace" )
{
m_thread = boost::shared_ptr<boost::thread> ( new boost::thread ( boost::bind ( &Trace::threadMain, this ) ) );
}
Trace::~Trace()
{
// stop thread
m_hasWork = false;
}
void Trace::add_Trace ( boost::shared_ptr<interface::ITraceable> trace )
{
// Add ITraceable object to the queue
{
// lock queue
{
boost::lock_guard<boost::mutex> lock ( m_lock );
m_queue.push_back ( trace );
}
m_condition.notify_one();
}
}
void Trace::threadMain()
{
boost::unique_lock<boost::mutex> lock ( m_lock );
while ( m_hasWork )
{
while ( m_queue.size() == 0 )
{
m_condition.wait ( lock );
}
this->processTraces();
}
}
void Trace::processTraces()
{
QueueType local_queue;
// Lock queue and copy
{
boost::lock_guard<boost::mutex> lock ( m_lock );
std::copy ( m_queue.begin(), m_queue.end(), local_queue.begin() );
}
for ( QueueType::iterator pos = local_queue.begin();
pos != local_queue.end();
pos++ )
{
// Process ITraceable object and write to a file
}
}
} /* namespace trace */
} /* namespace myproject */
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net