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 */