Well I had a chance to sit down and see what was going on with my logging project. What I found out is that the call to thread::join in the destructor of my logging class is never returning even though the thread was signaled to stop running. Below is the code. Since I am new to boost threads I am sure I am making a fundamental mistake. I compiled this project with boost 1.35 and gcc 4.3.3. Stephen ----------------------- #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 <boost/thread/once.hpp> #include <boost/scoped_ptr.hpp> #include <boost/type_traits/aligned_storage.hpp> #include <boost/bind.hpp> #include <boost/format.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/cstdint.hpp> #include <fstream> #include <sstream> #include <vector> namespace myproject { namespace interface { class ITraceable { public: typedef boost::shared_ptr<ITraceable> ptr_t; virtual std::string get_Formatted_String() = 0; }; } // namespace interface } // namespace myproject namespace myproject { namespace trace { class StringTraceable : public interface::ITraceable { public: StringTraceable ( boost::uint32_t area, boost::uint32_t level, std::string name ) : m_area ( area ), m_level ( level ), m_name ( name ) {} virtual ~StringTraceable(){} virtual std::string get_Formatted_String() { return m_name; } private: boost::uint32_t m_area; boost::uint32_t m_level; std::string m_name; }; template <typename UnsignedType> class NumberTraceable : public interface::ITraceable { public: NumberTraceable ( boost::uint32_t area, boost::uint32_t level, std::string name, UnsignedType line ) : m_area ( area ), m_level ( level ), m_name ( name ), m_line ( line ) {} virtual ~NumberTraceable(){} virtual std::string get_Formatted_String() { return m_name; } private: boost::uint32_t m_area; boost::uint32_t m_level; std::string m_name; UnsignedType m_line; }; template <typename T> struct storage_for { boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value> data; }; 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; namespace myproject { namespace trace { /* Idea taken from http://www.codeproject.com/debug/xytrace.asp * (28 Jan 2002 - Xiangyang Liu) * * I have modified this so that we don't use varargs and use constant types */ class Trace_State { public: typedef boost::shared_ptr<Trace_State> ptr_t; Trace_State(); virtual ~Trace_State(); Trace_State ( std::string name, std::string prefix ); void set_Trace_File_Name ( std::string name ); void set_Trace_File_Prefix ( std::string name ); void set_Trace_Level ( boost::uint32_t level ); void set_Trace_Area_Mask ( boost::uint32_t mask ); void open_Trace_File ( void ); std::string get_ID_String ( void ); void close_Trace_File ( void ); boost::uint32_t get_Trace_Level ( void ) const; boost::uint32_t get_Trace_Area_Mask ( void ) const; bool is_Valid_Level ( boost::uint32_t lvl ); bool is_Valid_Area_Mask ( boost::uint32_t mask ); void write_Message ( boost::uint32_t level, interface::ITraceable::ptr_t trace ); private: std::string m_file_prefix; std::string m_file_name; std::ofstream m_log_stream; }; } /* namespace trace */ } /* namespace trace */ namespace myproject { namespace trace { Trace_State::Trace_State() : m_file_prefix ( "Trace" ), m_file_name ( "" ) {} Trace_State::Trace_State( std::string name, std::string prefix ) : m_file_prefix ( prefix ), m_file_name ( name ) {} Trace_State::~Trace_State() { this->close_Trace_File(); } void Trace_State::set_Trace_File_Name ( std::string name ) { } void Trace_State::set_Trace_File_Prefix ( std::string name ) { } bool Trace_State::is_Valid_Level ( boost::uint32_t lvl ) { return true; } bool Trace_State::is_Valid_Area_Mask ( boost::uint32_t ) { return true; } void Trace_State::set_Trace_Level ( boost::uint32_t level ) { } void Trace_State::set_Trace_Area_Mask ( boost::uint32_t mask ) { } void Trace_State::open_Trace_File ( void ) { if ( ! m_log_stream.is_open() ) { if ( m_file_name.empty() ) { // Create file name std::stringstream name; name << boost::format("%s_%s.txt") % m_file_prefix % this->get_ID_String(); m_file_name = name.str(); } m_log_stream.open ( m_file_name.c_str() ); } } std::string Trace_State::get_ID_String ( void ) { // Create id string std::stringstream name; // Get current time boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); std::tm tm_ref = boost::posix_time::to_tm ( now ); boost::gregorian::date today = now.date(); name << boost::format ( "%1%_%2%:%3%:%4%" ) % boost::gregorian::to_iso_extended_string ( today ) % tm_ref.tm_hour % tm_ref.tm_min % tm_ref.tm_sec; return name.str(); } void Trace_State::close_Trace_File ( void ) { if ( m_log_stream.is_open() ) { m_log_stream.close(); } } boost::uint32_t Trace_State::get_Trace_Level ( void ) const { return 0; } boost::uint32_t Trace_State::get_Trace_Area_Mask ( void ) const { return 0; } void Trace_State::write_Message ( boost::uint32_t level, boost::shared_ptr<interface::ITraceable> trace ) { // write message } } /* namespace trace */ } /* namespace trace */ 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: ~Trace(); static void write_Trace ( boost::uint32_t area, boost::uint32_t level, std::string name ) { interface::ITraceable::ptr_t string_ptr ( new StringTraceable ( area, level, name ) ); Trace::Instance().add_Trace ( string_ptr ); } template <typename UnsignedType> static void write_Trace ( boost::uint32_t area, boost::uint32_t level, std::string format, UnsignedType value ) { interface::ITraceable::ptr_t unsigned_ptr ( new NumberTraceable<UnsignedType> ( area, level, format, value ) ); Trace::Instance().add_Trace ( unsigned_ptr ); } void add_Trace ( interface::ITraceable::ptr_t trace ); void set_Trace_Level ( boost::uint32_t level ); void set_Trace_Area_Mask ( boost::uint32_t mask ); void open_Trace_File (); void close_Trace_File(); 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 < myproject::interface::ITraceable::ptr_t > QueueType; QueueType m_queue; // Thread variables boost::shared_ptr<boost::thread> m_thread; bool m_hasWork; // Logging Trace_State m_state; }; } /* namespace trace */ } /* namespace myproject */ namespace myproject { namespace trace { Trace::Trace () : m_hasWork ( true ), m_state ( "Trace", "Trace" ) { // start thread m_thread = boost::shared_ptr<boost::thread> ( new boost::thread ( boost::bind ( &Trace::threadMain, this ) ) ); } Trace::~Trace() { // stop thread { boost::lock_guard<boost::mutex> lock ( m_lock ); m_hasWork = false; } m_condition.notify_one(); m_thread->join(); } void Trace::add_Trace ( interface::ITraceable::ptr_t trace ) { // 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 ( m_queue.begin(), m_queue.end() ); m_queue.clear(); for ( QueueType::iterator pos = local_queue.begin(); pos != local_queue.end(); pos++ ) { // Write message } } void Trace::set_Trace_Level ( boost::uint32_t level ) { m_state.set_Trace_Level ( level ); } void Trace::set_Trace_Area_Mask ( boost::uint32_t mask ) { m_state.set_Trace_Area_Mask ( mask ); } void Trace::open_Trace_File() { m_state.open_Trace_File(); } void Trace::close_Trace_File() { m_state.close_Trace_File(); } } /* namespace trace */ } /* namespace myproject */ int main ( int, char** ) { myproject::trace::Trace::Instance().open_Trace_File(); myproject::interface::ITraceable::ptr_t tmp_ptr ( new myproject::trace::StringTraceable( 0, 0, "" ) ); myproject::trace::Trace::Instance().add_Trace ( tmp_ptr ); myproject::trace::Trace::Instance().close_Trace_File(); }