Boost logo

Boost :

From: James Ahlborn (james.ahlborn_at_[hidden])
Date: 2004-09-15 10:42:05


hey,
I was wondering if any of the boost developers could tell me if recursive
mutexes are supposed to work with conditions? From the code, it would seem to
be the case, however in reality things aren't so happy. I have a fairly small
test case which shows that the locking doesn't work if you recursively lock a
mutex and then try to do a condition wait/notify. I'm testing this on red hat
7.3 and fedora core 2. My guess as to why it's broken is because the boost
condition uses posix recursive mutexes internally, which also seem to fail the
recursive mutex/condition test (at least on the OS's mentioned above). Anyone
have any thoughts on this?

I'll include my test case below. The error (for me) happens that when Thread2
releases the "inner" lock, Thread1 proceeds, even though Thread2 should still be
holding the lock. (ps- i'm aware that there are some mem leaks in the program,
i just simplified it for testing).

thanks,
-james

-------------------------------------------------------

#include <string>
#include <iostream.h>
#include <boost/thread.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/bind.hpp>

using namespace boost;
using namespace boost::detail::thread;

class ThreadBase
  : private boost::noncopyable
{
public:
  
  void start()
  {
    m_thread.reset(new boost::thread(boost::bind(&ThreadBase::run,
                                                 m_weakThis.lock())));
  }

  void join()
  {
    m_thread->join();
  }
  
protected:

  virtual void run() = 0;
  
  ThreadBase() : m_thread(), m_weakThis() {}
  virtual ~ThreadBase() {}
  
  void initWeakThis(boost::weak_ptr<ThreadBase> weakThis)
  {
    m_weakThis = weakThis;
  }
  
  boost::shared_ptr<boost::thread> m_thread;
  boost::weak_ptr<ThreadBase> m_weakThis;
  
private:

};

class Thread2 : public ThreadBase
{
  recursive_mutex* _mutex;
  condition* _cond;

protected:
  Thread2(recursive_mutex* mutex,
          condition* cond) : ThreadBase(), _mutex(mutex), _cond(cond)
  {}

public:
  static shared_ptr<Thread2> create(recursive_mutex* mutex,
                                    condition* cond)
  {
    shared_ptr<Thread2> tmp(new Thread2(mutex, cond));
    tmp->initWeakThis(tmp);
    return tmp;
  }

  virtual ~Thread2() { cerr << "Thread2 dying\n"; }
  
  
  virtual void run()
  {
    cerr << "Thread2 acquiring lock(1)\n";

    recursive_mutex::scoped_lock sl1(*_mutex);

    cerr << "Thread2 acquiring lock(2)\n";
    {
      recursive_mutex::scoped_lock sl2(*_mutex);

      cerr << "Thread2 sleeping...\n";
      ::sleep(5);
      
      cerr << "Thread2 signalling...\n";
      _cond->notify_all();

      cerr << "Thread2 releasing lock(2)\n";
    }

    cerr << "Thread2 sleeping (again)...\n";
    ::sleep(5);
      
    cerr << "Thread2 releasing lock(1)\n";
  }
  
};

class Thread1 : public ThreadBase
{
  recursive_mutex _mutex;
  condition _cond;
  
protected:
  Thread1() : ThreadBase()
  {}

public:
  static shared_ptr<Thread1> create()
  {
    shared_ptr<Thread1> tmp(new Thread1());
    tmp->initWeakThis(tmp);
    return tmp;
  }

  virtual ~Thread1() { cerr << "Thread1 dying\n"; }
  
  virtual void run()
  {
    cerr << "Thread1 acquiring lock(1)\n";

    scoped_lock<recursive_mutex> sl1(_mutex);

    cerr << "Thread1 acquiring lock(2)\n";
    {
      scoped_lock<recursive_mutex> sl2(_mutex);

      
      cerr << "Thread1 starting Thread2\n";
      shared_ptr<Thread2> t2 = Thread2::create(&_mutex, &_cond);
      t2->start();
      t2.reset();

      cerr << "Thread1 waiting\n";
      _cond.wait(sl2);
      
      cerr << "Thread1 releasing lock(2)\n";
      
    }

    cerr << "Thread1 releasing lock(1)\n";
  }
  
};

int main(int argc, char** argv)
{
  
  
  cerr << "Main Starting...\n";

  shared_ptr<Thread1> t1 = Thread1::create();
  t1->start();
  t1->join();

  cerr << "Main First Run\n";

  
  // run it again
  t1->start();
  t1->join();
  

  t1.reset();
  cerr << "Main Done\n";
  
  return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk