Personally I will first try to output few lines of simple message to std err, see if if key codes (i.e. add_Trace(), processTraces(), constructor and destructor, ...) was executed AND in the correct order, providing that the problem is not too race to replicate. If it does not help then only I will use gdb for stepping through it (<a href="http://www.google.com.sg/search?q=gdb+tutorial">http://www.google.com.sg/search?q=gdb+tutorial</a>). Honestly I&#39;m relatively green in using gdb especially in debugging multi-threaded code so please share your approach :)<br>
<br><br><div class="gmail_quote">On Sun, Jan 24, 2010 at 5:09 AM, Stephen Torri <span dir="ltr">&lt;<a href="mailto:storri@torri.org">storri@torri.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
In the logging example I have been working on to learn more about boost<br>
threads I have run across what I think is a race condition. If I compile<br>
and run this sample program it will sometimes write out an error message<br>
to a file. For example:<br>
<br>
2010-01-23_16:2:23 (pid=10948 thread_id=0x92ce448) (II) funky<br>
<br>
Other times I see the file is blank. So can I say conclusively that its<br>
a race condition? No. Either what is happening is a race condition where<br>
the file is closed before the contents are written to the file or<br>
something else is causing the logging message to be written sometimes<br>
and not at others.<br>
<br>
So to recap:<br>
<br>
--- How can you track down a race condition?<br>
--- Can I use &#39;strace&#39; or &#39;gdb&#39;?<br>
<br>
Stephen<br>
<br>
-------------------------------------------<br>
#include &lt;boost/cstdint.hpp&gt;<br>
#include &lt;boost/shared_ptr.hpp&gt;<br>
#include &lt;boost/thread/mutex.hpp&gt;<br>
#include &lt;boost/thread/condition_variable.hpp&gt;<br>
#include &lt;boost/thread/thread.hpp&gt;<br>
#include &lt;boost/utility.hpp&gt;<br>
#include &lt;boost/thread/once.hpp&gt;<br>
#include &lt;boost/scoped_ptr.hpp&gt;<br>
#include &lt;boost/type_traits/aligned_storage.hpp&gt;<br>
#include &lt;boost/bind.hpp&gt;<br>
#include &lt;boost/format.hpp&gt;<br>
#include &lt;boost/date_time/posix_time/posix_time.hpp&gt;<br>
#include &lt;boost/cstdint.hpp&gt;<br>
<br>
#include &lt;fstream&gt;<br>
#include &lt;sstream&gt;<br>
#include &lt;vector&gt;<br>
<br>
namespace myproject { namespace api {<br>
<br>
 � �/*!<br>
 � � * \brief Trace level constants<br>
 � � * \date 2003<br>
 � � * \author Stephen Torri<br>
 � � */<br>
 � �class TraceLevel {<br>
 � �public:<br>
 � � �enum Values {<br>
 � � � �NONE = 0,<br>
 � � � �WARN = 10,<br>
 � � � �ERROR = 20,<br>
 � � � �INFO = 30,<br>
 � � � �DEBUG = 40,<br>
 � � � �DETAIL = 50,<br>
 � � � �DATA = 60<br>
 � � �};<br>
 � �};<br>
<br>
 �} // namespace api<br>
} // namespace myproject<br>
<br>
namespace myproject { namespace interface {<br>
<br>
 � �class ITraceable {<br>
 � �public:<br>
<br>
 � � �typedef boost::shared_ptr&lt;ITraceable&gt; ptr_t;<br>
<br>
 � � �virtual std::string get_Formatted_String() = 0;<br>
<br>
 � � �virtual boost::uint32_t getLevel() = 0;<br>
<br>
 � � �virtual boost::uint32_t getPID() = 0;<br>
<br>
 � � �virtual boost::thread::id getThreadID() = 0;<br>
 � �};<br>
 �} // namespace interface<br>
} // namespace myproject<br>
<br>
namespace myproject { namespace trace {<br>
<br>
 � �class StringTraceable : public interface::ITraceable<br>
 � �{<br>
 � �public:<br>
<br>
 � � �StringTraceable ( boost::uint32_t area, boost::uint32_t level, std::string name )<br>
 � � � �: m_area ( area ),<br>
 � � � � �m_level ( level ),<br>
 � � � � �m_name ( name )<br>
 � � �{<br>
#ifndef WIN32<br>
 � � � �m_pid = getpid();<br>
#else<br>
 � � � �m_pid = GetCurrentProcessId();<br>
#endif /* WIN32 */<br>
<br>
 � � � �m_thread_id = boost::this_thread::get_id();<br>
 � � �}<br>
<br>
 � � �virtual ~StringTraceable(){}<br>
<br>
 � � �virtual std::string get_Formatted_String()<br>
 � � �{<br>
 � � � �return m_name;<br>
 � � �}<br>
<br>
 � � �virtual boost::uint32_t getLevel()<br>
 � � �{<br>
 � � � �return m_level;<br>
 � � �}<br>
<br>
 � � �virtual boost::uint32_t getPID()<br>
 � � �{<br>
 � � � �return m_pid;<br>
 � � �}<br>
<br>
 � � �virtual boost::thread::id getThreadID()<br>
 � � �{<br>
 � � � �return m_thread_id;<br>
 � � �}<br>
<br>
 � �private:<br>
<br>
 � � �boost::uint32_t m_area;<br>
 � � �boost::uint32_t m_level;<br>
 � � �boost::uint32_t m_pid;<br>
 � � �boost::thread::id m_thread_id;<br>
 � � �std::string m_name;<br>
 � �};<br>
<br>
 � �template &lt;typename UnsignedType&gt;<br>
 � �class NumberTraceable : public interface::ITraceable<br>
 � �{<br>
 � �public:<br>
<br>
 � � �NumberTraceable ( boost::uint32_t area, boost::uint32_t level, std::string name, UnsignedType line )<br>
 � � � �: m_area ( area ),<br>
 � � � � �m_level ( level ),<br>
 � � � � �m_name ( name ),<br>
 � � � � �m_line ( line )<br>
 � � �{<br>
#ifndef WIN32<br>
 � � � �m_pid = getpid();<br>
#else<br>
 � � � �m_pid = GetCurrentProcessId();<br>
#endif /* WIN32 */<br>
<br>
 � � � �m_thread_id = boost::this_thread::get_id();<br>
 � � �}<br>
<br>
 � � �virtual ~NumberTraceable(){}<br>
<br>
 � � �virtual std::string get_Formatted_String()<br>
 � � �{<br>
 � � � �return m_name;<br>
 � � �}<br>
<br>
 � � �virtual boost::uint32_t getLevel()<br>
 � � �{<br>
 � � � �return m_level;<br>
 � � �}<br>
<br>
 � � �virtual boost::uint32_t getPID()<br>
 � � �{<br>
 � � � �return m_pid;<br>
 � � �}<br>
<br>
 � � �virtual boost::thread::id getThreadID()<br>
 � � �{<br>
 � � � �return m_thread_id;<br>
 � � �}<br>
<br>
 � �private:<br>
<br>
 � � �boost::uint32_t m_area;<br>
 � � �boost::uint32_t m_level;<br>
 � � �boost::uint32_t m_pid;<br>
 � � �boost::thread::id m_thread_id;<br>
 � � �std::string m_name;<br>
 � � �UnsignedType m_line;<br>
 � �};<br>
<br>
<br>
 � �template &lt;typename T&gt;<br>
 � �struct storage_for<br>
 � �{<br>
 � � �boost::aligned_storage&lt;sizeof(T), boost::alignment_of&lt;T&gt;::value&gt; data;<br>
 � �};<br>
<br>
 � �template &lt;typename T&gt;<br>
 � �class Singleton : boost::noncopyable<br>
 � �{<br>
 � �public:<br>
<br>
 � � �static T&amp; Instance()<br>
 � � �{<br>
 � � � �boost::call_once ( init, m_flag );<br>
 � � � �return *m_obj;<br>
 � � �}<br>
<br>
 � � �static void init ()<br>
 � � �{<br>
 � � � �m_obj.reset ( new T() );<br>
 � � �}<br>
<br>
 � �protected:<br>
<br>
 � � �~Singleton(){}<br>
 � � �Singleton(){}<br>
<br>
 � �private:<br>
<br>
 � � �static boost::scoped_ptr&lt;T&gt; m_obj;<br>
 � � �static boost::once_flag m_flag;<br>
 � �};<br>
<br>
 �} // namespace trace<br>
} // namespace trace<br>
<br>
template &lt;typename T&gt; boost::scoped_ptr&lt;T&gt; myproject::trace::Singleton&lt;T&gt;::m_obj ( 0 );<br>
template &lt;typename T&gt; boost::once_flag myproject::trace::Singleton&lt;T&gt;::m_flag = BOOST_ONCE_INIT;<br>
<br>
namespace myproject { namespace trace {<br>
<br>
 � �class Trace_State_Utils {<br>
 � �public:<br>
<br>
 � � �static std::string get_Level_String ( boost::uint32_t level )<br>
 � � �{<br>
 � � � �// Write message prefix<br>
 � � � �if ( level == api::TraceLevel::WARN )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(WW) &quot;;<br>
 � � � � � �}<br>
 � � � �else if ( level == api::TraceLevel::ERROR )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(EE) &quot;;<br>
 � � � � � �}<br>
 � � � �else if ( level == api::TraceLevel::INFO )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(II) &quot;;<br>
 � � � � � �}<br>
 � � � �else if ( level == api::TraceLevel::DEBUG )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(DEBUG) &quot;;<br>
 � � � � � �}<br>
 � � � �else if ( level == api::TraceLevel::DETAIL )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(DETAIL) &quot;;<br>
 � � � � � �}<br>
 � � � �else if ( level == api::TraceLevel::DATA )<br>
 � � � � � �{<br>
 � � � � � � � �return &quot;(DATA) &quot;;<br>
 � � � � � �}<br>
 � � � �else<br>
 � � � � � �{<br>
 � � � � � � � �// We should not be here<br>
 � � � � � � � �abort();<br>
 � � � � � �}<br>
 � � �}<br>
 � �};<br>
<br>
<br>
 � �/* Idea taken from <a href="http://www.codeproject.com/debug/xytrace.asp" target="_blank">http://www.codeproject.com/debug/xytrace.asp</a><br>
 � � * (28 Jan 2002 - Xiangyang Liu)<br>
 � � *<br>
 � � * I have modified this so that we don&#39;t use varargs and use constant types<br>
 � � */<br>
 � �class Trace_State {<br>
 � �public:<br>
<br>
 � � �typedef boost::shared_ptr&lt;Trace_State&gt; ptr_t;<br>
<br>
 � � �Trace_State()<br>
 � � � �: m_file_prefix ( &quot;Trace&quot; )<br>
 � � �{}<br>
<br>
<br>
 � � �virtual ~Trace_State();<br>
<br>
 � � �Trace_State ( std::string prefix );<br>
<br>
 � � �void set_Trace_File_Prefix ( std::string name );<br>
<br>
 � � �void set_Trace_Level ( boost::uint32_t level );<br>
<br>
 � � �void set_Trace_Area_Mask ( boost::uint32_t mask );<br>
<br>
 � � �void open_Trace_File ( void );<br>
<br>
 � � �std::string get_ID_String ( void );<br>
<br>
 � � �void close_Trace_File ( void );<br>
<br>
 � � �boost::uint32_t get_Trace_Level ( void ) const;<br>
<br>
 � � �boost::uint32_t get_Trace_Area_Mask ( void ) const;<br>
<br>
 � � �bool is_Valid_Level ( boost::uint32_t lvl );<br>
<br>
 � � �bool is_Valid_Area_Mask ( boost::uint32_t mask );<br>
<br>
<br>
 � � �void write_Message ( interface::ITraceable::ptr_t trace )<br>
 � � �{<br>
 � � � �// Write ID<br>
 � � � �m_log_stream &lt;&lt; boost::format(&quot;%s (pid=%d thread_id=&quot; )<br>
 � � � � �% this-&gt;get_ID_String()<br>
 � � � � �% trace-&gt;getPID()<br>
 � � � � � � � � � � &lt;&lt; trace-&gt;getThreadID()<br>
 � � � � � � � � � � &lt;&lt; &quot;) &quot;<br>
 � � � � � � � � � � &lt;&lt; std::flush;<br>
<br>
 � � � �m_log_stream &lt;&lt; Trace_State_Utils::get_Level_String(trace-&gt;getLevel()) &lt;&lt; trace-&gt;get_Formatted_String() &lt;&lt; std::endl &lt;&lt; std::flush;<br>
 � � �}<br>
<br>
<br>
 � �private:<br>
<br>
 � � �std::string m_file_prefix;<br>
<br>
 � � �std::ofstream m_log_stream;<br>
 � �};<br>
<br>
 �} /* namespace trace */<br>
} /* namespace trace */<br>
<br>
<br>
namespace myproject { namespace trace {<br>
<br>
 � �Trace_State::Trace_State( std::string prefix )<br>
 � � � �: m_file_prefix ( prefix )<br>
 � �{}<br>
<br>
 � �Trace_State::~Trace_State()<br>
 � �{<br>
 � � � �this-&gt;close_Trace_File();<br>
 � �}<br>
<br>
 � �void<br>
 � �Trace_State::set_Trace_File_Prefix ( std::string name )<br>
 � �{<br>
 � �}<br>
<br>
 � �bool<br>
 � �Trace_State::is_Valid_Level ( boost::uint32_t lvl )<br>
 � �{<br>
 � � �return true;<br>
 � �}<br>
<br>
 � �bool<br>
 � �Trace_State::is_Valid_Area_Mask ( boost::uint32_t )<br>
 � �{<br>
 � � �return true;<br>
 � �}<br>
<br>
 � �void<br>
 � �Trace_State::set_Trace_Level ( boost::uint32_t level )<br>
 � �{<br>
 � �}<br>
<br>
 � �void<br>
 � �Trace_State::set_Trace_Area_Mask ( boost::uint32_t mask )<br>
 � �{<br>
 � �}<br>
<br>
 � �void<br>
 � �Trace_State::open_Trace_File ( void )<br>
 � �{<br>
 � � � �if ( ! m_log_stream.is_open() )<br>
 � � � � � �{<br>
 � � � � � � �// Create file name<br>
 � � � � � � �std::stringstream name;<br>
<br>
 � � � � � � �name &lt;&lt; boost::format(&quot;%s_%s.txt&quot;)<br>
 � � � � � � � �% m_file_prefix<br>
 � � � � � � � �% this-&gt;get_ID_String();<br>
<br>
 � � � � � � �std::string file_name = name.str();<br>
<br>
 � � � � � � �m_log_stream.open ( file_name.c_str() );<br>
 � � � � � �}<br>
 � �}<br>
<br>
 � �std::string<br>
 � �Trace_State::get_ID_String ( void )<br>
 � �{<br>
 � � � �// Create id string<br>
 � � � �std::stringstream name;<br>
<br>
 � � � �// Get current time<br>
 � � � �boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();<br>
<br>
 � � � �std::tm tm_ref = boost::posix_time::to_tm ( now );<br>
<br>
 � � � �boost::gregorian::date today = now.date();<br>
<br>
 � � � �name &lt;&lt; boost::format ( &quot;%1%_%2%:%3%:%4%&quot; )<br>
 � � � � � �% boost::gregorian::to_iso_extended_string ( today )<br>
 � � � � � �% tm_ref.tm_hour<br>
 � � � � � �% tm_ref.tm_min<br>
 � � � � � �% tm_ref.tm_sec;<br>
<br>
 � � � �return name.str();<br>
 � �}<br>
<br>
 � �void<br>
 � �Trace_State::close_Trace_File ( void )<br>
 � �{<br>
 � � � �if ( m_log_stream.is_open() )<br>
 � � � � � �{<br>
 � � � � � � �m_log_stream &lt;&lt; std::flush;<br>
<br>
 � � � � � � �m_log_stream.close();<br>
 � � � � � �}<br>
 � �}<br>
<br>
 � �boost::uint32_t<br>
 � �Trace_State::get_Trace_Level ( void ) const<br>
 � �{<br>
 � � � �return 0;<br>
 � �}<br>
<br>
 � �boost::uint32_t<br>
 � �Trace_State::get_Trace_Area_Mask ( void ) const<br>
 � �{<br>
 � � � �return 0;<br>
 � �}<br>
<br>
} /* namespace trace */<br>
} /* namespace trace */<br>
<br>
<br>
<br>
namespace myproject { namespace trace {<br>
<br>
 � �//<br>
 � �// Turn Trace into a singleton class that contains a worker thread<br>
 � �// - Wait for data<br>
 � �// � - If data exists then process<br>
 � �// � - Else wait<br>
 � �// Add method for adding a ITraceable object. This will lock the logging vector, add<br>
 � �// �element then signal the boost condition variable<br>
 � �class Trace : public Singleton&lt;Trace&gt; {<br>
<br>
 � � �friend class Singleton&lt;Trace&gt;;<br>
<br>
 � �public:<br>
<br>
 � � �~Trace();<br>
<br>
 � � �static void write_Trace ( boost::uint32_t area, boost::uint32_t level, std::string name )<br>
 � � �{<br>
 � � � �interface::ITraceable::ptr_t string_ptr ( new StringTraceable ( area, level, name ) );<br>
 � � � �Trace::Instance().add_Trace ( string_ptr );<br>
 � � �}<br>
<br>
 � � �template &lt;typename UnsignedType&gt;<br>
 � � �static void write_Trace ( boost::uint32_t area, boost::uint32_t level, std::string format, UnsignedType value )<br>
 � � �{<br>
 � � � �interface::ITraceable::ptr_t unsigned_ptr ( new NumberTraceable&lt;UnsignedType&gt; ( area, level, format, value ) );<br>
 � � � �Trace::Instance().add_Trace ( unsigned_ptr );<br>
 � � �}<br>
<br>
 � � �void add_Trace ( interface::ITraceable::ptr_t trace );<br>
<br>
 � � �void set_Trace_Level ( boost::uint32_t level );<br>
<br>
 � � �void set_Trace_Area_Mask ( boost::uint32_t mask );<br>
<br>
 � � �void open_Trace_File ();<br>
<br>
 � � �void close_Trace_File();<br>
<br>
 � �private:<br>
<br>
 � � �Trace();<br>
<br>
 � � �// Worker thread functions<br>
 � � �void threadMain();<br>
 � � �void processTraces(boost::unique_lock&lt;boost::mutex&gt;&amp; lock);<br>
<br>
 � � �// Synchronization variables<br>
 � � �boost::mutex m_lock;<br>
 � � �boost::condition_variable m_condition;<br>
<br>
 � � �// Data variables<br>
 � � �typedef std::vector &lt; myproject::interface::ITraceable::ptr_t &gt; QueueType;<br>
 � � �QueueType m_queue;<br>
<br>
 � � �// Thread variables<br>
 � � �boost::shared_ptr&lt;boost::thread&gt; m_thread;<br>
 � � �bool m_hasWork;<br>
<br>
 � � �// Logging<br>
 � � �Trace_State m_state;<br>
 � �};<br>
<br>
 �} /* namespace trace */<br>
} /* namespace myproject */<br>
<br>
namespace myproject { namespace trace {<br>
<br>
 � �Trace::Trace ()<br>
 � � �: m_hasWork ( true ),<br>
 � � � �m_state ( &quot;Trace&quot; )<br>
 � �{<br>
 � � �// start thread<br>
 � � �m_thread = boost::shared_ptr&lt;boost::thread&gt; ( new boost::thread ( boost::bind ( &amp;Trace::threadMain, this ) ) );<br>
 � �}<br>
<br>
 � �Trace::~Trace()<br>
 � �{<br>
 � � �// stop thread<br>
 � � �{<br>
 � � � �boost::lock_guard&lt;boost::mutex&gt; lock ( m_lock );<br>
 � � � �m_hasWork = false;<br>
 � � �}<br>
<br>
 � � �m_condition.notify_one();<br>
<br>
 � � �m_thread-&gt;join();<br>
 � �}<br>
<br>
 � �void Trace::add_Trace ( interface::ITraceable::ptr_t trace )<br>
 � �{<br>
 � � �// lock queue<br>
 � � �{<br>
 � � � �boost::lock_guard&lt;boost::mutex&gt; lock ( m_lock );<br>
 � � � �m_queue.push_back ( trace );<br>
 � � �}<br>
<br>
 � � �m_condition.notify_one();<br>
 � �}<br>
<br>
 � �void Trace::threadMain()<br>
 � �{<br>
 � � �boost::unique_lock&lt;boost::mutex&gt; lock ( m_lock );<br>
<br>
 � � �while ( m_hasWork )<br>
 � � � �{<br>
 � � � � �if ( m_queue.size() == 0 )<br>
 � � � � � �{<br>
 � � � � � � �m_condition.wait ( lock );<br>
 � � � � � �}<br>
 � � � � �else<br>
 � � � � � �{<br>
 � � � � � � �this-&gt;processTraces(lock);<br>
 � � � � � �}<br>
 � � � �}<br>
 � �}<br>
<br>
 � �void Trace::processTraces(boost::unique_lock&lt;boost::mutex&gt;&amp; lock)<br>
 � �{<br>
 � � �assert ( lock.owns_lock() );<br>
<br>
 � � �QueueType local_queue ( m_queue.begin(), m_queue.end() );<br>
 � � �m_queue.clear();<br>
<br>
 � � �lock.unlock();<br>
<br>
 � � �for ( QueueType::iterator pos = local_queue.begin();<br>
 � � � � � �pos != local_queue.end();<br>
 � � � � � �pos++ )<br>
 � � � �{<br>
 � � � � �myproject::interface::ITraceable::ptr_t trace_obj = (*pos);<br>
 � � � � �m_state.write_Message ( trace_obj );<br>
 � � � �}<br>
<br>
 � � �lock.lock();<br>
 � �}<br>
<br>
 � �void Trace::set_Trace_Level ( boost::uint32_t level )<br>
 � �{<br>
 � � �m_state.set_Trace_Level ( level );<br>
 � �}<br>
<br>
 � �void Trace::set_Trace_Area_Mask ( boost::uint32_t mask )<br>
 � �{<br>
 � � �m_state.set_Trace_Area_Mask ( mask );<br>
 � �}<br>
<br>
 � �void Trace::open_Trace_File()<br>
 � �{<br>
 � � �m_state.open_Trace_File();<br>
 � �}<br>
<br>
 � �void Trace::close_Trace_File()<br>
 � �{<br>
 � � �m_state.close_Trace_File();<br>
 � �}<br>
<br>
 �} /* namespace trace */<br>
} /* namespace myproject */<br>
<br>
<br>
int main ( int, char** )<br>
{<br>
 �namespace trace = myproject::trace;<br>
 �namespace api = myproject::api;<br>
<br>
 �trace::Trace::Instance().open_Trace_File();<br>
<br>
 �myproject::interface::ITraceable::ptr_t tmp_ptr ( new trace::StringTraceable( 0, api::TraceLevel::INFO, &quot;funky&quot; ) );<br>
<br>
 �trace::Trace::Instance().add_Trace ( tmp_ptr );<br>
<br>
 �trace::Trace::Instance().close_Trace_File();<br>
}<br>
<br>
<br>
_______________________________________________<br>
Boost-users mailing list<br>
<a href="mailto:Boost-users@lists.boost.org">Boost-users@lists.boost.org</a><br>
<a href="http://lists.boost.org/mailman/listinfo.cgi/boost-users" target="_blank">http://lists.boost.org/mailman/listinfo.cgi/boost-users</a><br>
</blockquote></div><br>