Search code examples
c++boostboost-thread

does boost::thread::timed_join(0) acquire a lock?


I need to check if my boost::thread I've created is running from another thread. This SO post explains you can do this by calling:

boost::posix_time::seconds waitTime(0);
myBoostThread.timed_join(waitTime);

I can't have any critical sections in my client thread. Can I guarantee that timed_join() with 0 time argument be lock free?


Solution

  • Boost.Thread provides no guarantees about a lock-free timed_join(). However, the implementation, which is always subject to change:

    • Boost.Thread acquires a mutex for pthreads, then performs a timed wait on a condition variable.
    • Boost.Thread calls WaitForMultipleObjects for windows. Its documentation indicates that it will always return immediately. However, I do not know if the underlying OS implementation is lock-free.

    For an alternative, consider using atomic operations. While Boost 1.52 does not currently provide a public atomic library, both Boost.Smart_Ptr and Boost.Interprocess have atomic integers within their detail namespace. However, neither of these guarantee lock-free implementations, and one of the configurations for Boost.Smart_Ptr will lock with pthread mutex. Thus, you may need to consult your compiler and system's documentation to identify a lock-free implementation.

    Nevertheless, here is a small example using boost::detail::atomic_count:

    #include <boost/chrono.pp>
    #include <boost/detail/atomic_count.hpp>
    #include <boost/thread.hpp>
    
    // Use RAII to perform cleanup.
    struct count_guard
    {
      count_guard(boost::detail::atomic_count& count) : count_(count) {}
      ~count_guard() { --count_; }
      boost::detail::atomic_count& count_;
    };
    
    void thread_main(boost::detail::atomic_count& count)
    {
      // Place the guard on the stack. When the thread exits through either normal
      // means or the stack unwinding from an exception, the atomic count will be
      // decremented.
      count_guard decrement_on_exit(count);
      boost::this_thread::sleep_for(boost::chrono::seconds(5));
    }
    
    int main()
    {
      boost::detail::atomic_count count(1);
      boost::thread t(thread_main, boost::ref(count));
    
      // Check the count to determine if the thread has exited.
      while (0 != count)
      {
        std::cout << "Sleeping for 2 seconds." << std::endl;
        boost::this_thread::sleep_for(boost::chrono::seconds(2));
      }
    }
    

    In this case, the at_thread_exit() extension could be used as an alternative to using RAII.