void test_mutex_timed_lock(P &sm)

{
   {
      shared_val = 0;

      data<P> m1(1, sm, 3);
      data<P> m2(2, sm, 3);

      // Locker one launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tm1(thread_adapter<P>(&timed_wait_and_sleep, &m1, sm));

      //Wait 1*BaseSeconds
      boost::thread::sleep(xsecs(1*BaseSeconds));

      // Locker two launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tm2(thread_adapter<P>(&timed_wait_and_sleep, &m2, sm));

      //Wait completion
      tm1.join();
      tm2.join();

      //Both should succeed locking
      assert(m1.m_value == 1);
      assert(m2.m_value == 2);
   }
   {
      shared_val = 0;

      data<P> m1(1, sm, 3);
      data<P> m2(2, sm, 3);

      // Locker one launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tm1(thread_adapter<P>(&timed_wait_and_sleep, &m1, sm));

      //Wait 1*BaseSeconds
      boost::thread::sleep(xsecs(1*BaseSeconds));

      // Locker two launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tm2(thread_adapter<P>(&timed_wait_and_sleep, &m2, sm));

      //Wait completion
      tm1.join();
      tm2.join();

      //Both should succeed locking
      assert(m1.m_value == 1);
      assert(m2.m_value == 2);
   }
}
void test_try_sharable_mutex()
{
   SM mtx;

   data<SM> s1(1);
   data<SM> e1(2);
   data<SM> e2(3);

   // We start with some specialized tests for "try" behavior

   shared_val = 0;

   // Writer one launches, holds the lock for 3*BaseSeconds seconds.

   boost::thread tw1(thread_adapter<SM>(try_exclusive,&e1,mtx));

   // Reader one launches, "clearly" after writer #1 holds the lock
   //   and before it releases the lock.
   boost::thread::sleep(xsecs(1*BaseSeconds));
   boost::thread thr1(thread_adapter<SM>(try_shared,&s1,mtx));

   // Writer two launches in the same timeframe.
   boost::thread tw2(thread_adapter<SM>(try_exclusive,&e2,mtx));

   tw2.join();
   thr1.join();
   tw1.join();

   BOOST_INTERPROCES_CHECK(e1.m_value == 10);
   BOOST_INTERPROCES_CHECK(s1.m_value == -1);        // Try would return w/o waiting
   BOOST_INTERPROCES_CHECK(e2.m_value == -1);        // Try would return w/o waiting
}
void wait_and_sleep(void *arg, P &sm)
{
   data<P> *pdata = static_cast<data<P>*>(arg);
   boost::interprocess::scoped_lock<P> l(sm);
   boost::thread::sleep(xsecs(3*BaseSeconds));
   ++shared_val;
   pdata->m_value = shared_val;
}
void plain_exclusive(void *arg, SM &sm)
{
   data<SM> *pdata = static_cast<data<SM>*>(arg);
   boost::interprocess::scoped_lock<SM> l(sm);
   boost::thread::sleep(xsecs(3*BaseSeconds));
   shared_val += 10;
   pdata->m_value = shared_val;
}
void plain_shared(void *arg, SM &sm)
{
   data<SM> *pdata = static_cast<data<SM>*>(arg);
   boost::interprocess::sharable_lock<SM> l(sm);
   if(pdata->m_secs){
      boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds));
   }
   pdata->m_value = shared_val;
}
void try_exclusive(void *arg, SM &sm)
{
   data<SM> *pdata = static_cast<data<SM>*>(arg);
   boost::interprocess::scoped_lock<SM> l(sm, boost::interprocess::defer_lock);
   if (l.try_lock()){
      boost::thread::sleep(xsecs(3*BaseSeconds));
      shared_val += 10;
      pdata->m_value = shared_val;
   }
}
void timed_wait_and_sleep(void *arg, P &sm)
{
   data<P> *pdata = static_cast<data<P>*>(arg);
   boost::posix_time::ptime pt(delay(pdata->m_secs));
   boost::interprocess::scoped_lock<P> 
      l (sm, boost::interprocess::defer_lock);
   if (l.timed_lock(pt)){
      boost::thread::sleep(xsecs(3*BaseSeconds));
      ++shared_val;
      pdata->m_value = shared_val;
   }
}
void timed_shared(void *arg, SM &sm)
{
   data<SM> *pdata = static_cast<data<SM>*>(arg);
   boost::posix_time::ptime pt(delay(pdata->m_secs));
   boost::interprocess::sharable_lock<SM>
      l(sm, boost::interprocess::defer_lock);
   if (l.timed_lock(pt)){
      if(pdata->m_secs){
         boost::thread::sleep(xsecs(pdata->m_secs*BaseSeconds));
      }
      pdata->m_value = shared_val;
   }
}
void test_timed_sharable_mutex()
{
   SM m1, m2, m3, m4;
   SM *pm1, *pm2, *pm3, *pm4;

   if(SameObject){
      pm1 = pm2 = pm3 = pm4 = &m1;
   }
   else{
      pm1 = &m1;
      pm2 = &m2;
      pm3 = &m3;
      pm4 = &m4;
   }
   data<SM> s1(1,1*BaseSeconds);
   data<SM> s2(2,3*BaseSeconds);
   data<SM> e1(3,3*BaseSeconds);
   data<SM> e2(4,1*BaseSeconds);

   // We begin with some specialized tests for "timed" behavior

   shared_val = 0;

   // Writer one will hold the lock for 3*BaseSeconds seconds.
   boost::thread tw1(thread_adapter<SM>(timed_exclusive,&e1,*pm1));

   boost::thread::sleep(xsecs(1*BaseSeconds));
   // Writer two will "clearly" try for the lock after the readers
   //  have tried for it.  Writer will wait up 1*BaseSeconds seconds for the lock.
   //  This write will fail.
   boost::thread tw2(thread_adapter<SM>(timed_exclusive,&e2,*pm2));

   // Readers one and two will "clearly" try for the lock after writer
   //   one already holds it.  1st reader will wait 1*BaseSeconds seconds, and will fail
   //   to get the lock.  2nd reader will wait 3*BaseSeconds seconds, and will get
   //   the lock.

   boost::thread thr1(thread_adapter<SM>(timed_shared,&s1,*pm3));
   boost::thread thr2(thread_adapter<SM>(timed_shared,&s2,*pm4));

   tw1.join();
   thr1.join();
   thr2.join();
   tw2.join();

   assert(e1.m_value == 10);
   assert(s1.m_value == -1);
   assert(s2.m_value == 10);
   assert(e2.m_value == -1);
}
void test_try_sharable_mutex()
{
   SM m1, m2, m3;
   SM *pm1, *pm2, *pm3;

   if(SameObject){
      pm1 = pm2 = pm3 = &m1;
   }
   else{
      pm1 = &m1;
      pm2 = &m2;
      pm3 = &m3;
   }
   data<SM> s1(1);
   data<SM> e1(2);
   data<SM> e2(3);

   // We start with some specialized tests for "try" behavior

   shared_val = 0;

   // Writer one launches, holds the lock for 3*BaseSeconds seconds.

   boost::thread tw1(thread_adapter<SM>(try_exclusive,&e1,*pm1));

   // Reader one launches, "clearly" after writer #1 holds the lock
   //   and before it releases the lock.
   boost::thread::sleep(xsecs(1*BaseSeconds));
   boost::thread thr1(thread_adapter<SM>(try_shared,&s1,*pm2));

   // Writer two launches in the same timeframe.
   boost::thread tw2(thread_adapter<SM>(try_exclusive,&e2,*pm3));

   tw2.join();
   thr1.join();
   tw1.join();

   assert(e1.m_value == 10);
   assert(s1.m_value == -1);        // Try would return w/o waiting
   assert(e2.m_value == -1);        // Try would return w/o waiting
}
void test_timed_sharable_mutex()
{
   SM mtx;
   data<SM> s1(1,1*BaseSeconds);
   data<SM> s2(2,3*BaseSeconds);
   data<SM> e1(3,3*BaseSeconds);
   data<SM> e2(4,1*BaseSeconds);

   // We begin with some specialized tests for "timed" behavior

   shared_val = 0;

   // Writer one will hold the lock for 3*BaseSeconds seconds.
   boost::thread tw1(thread_adapter<SM>(timed_exclusive,&e1,mtx));

   boost::thread::sleep(xsecs(1*BaseSeconds));
   // Writer two will "clearly" try for the lock after the readers
   //  have tried for it.  Writer will wait up 1*BaseSeconds seconds for the lock.
   //  This write will fail.
   boost::thread tw2(thread_adapter<SM>(timed_exclusive,&e2,mtx));

   // Readers one and two will "clearly" try for the lock after writer
   //   one already holds it.  1st reader will wait 1*BaseSeconds seconds, and will fail
   //   to get the lock.  2nd reader will wait 3*BaseSeconds seconds, and will get
   //   the lock.

   boost::thread thr1(thread_adapter<SM>(timed_shared,&s1,mtx));
   boost::thread thr2(thread_adapter<SM>(timed_shared,&s2,mtx));

   tw1.join();
   thr1.join();
   thr2.join();
   tw2.join();

   BOOST_INTERPROCES_CHECK(e1.m_value == 10);
   BOOST_INTERPROCES_CHECK(s1.m_value == -1);
   BOOST_INTERPROCES_CHECK(s2.m_value == 10);
   BOOST_INTERPROCES_CHECK(e2.m_value == -1);
}
void test_plain_sharable_mutex()
{
   {
      shared_val = 0;
      SM mtx;
      data<SM> s1(1);
      data<SM> s2(2);
      data<SM> e1(1);
      data<SM> e2(2);

      // Writer one launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tw1(thread_adapter<SM>(plain_exclusive, &e1, mtx));

      // Writer two launches, tries to grab the lock, "clearly"
      //  after Writer one will already be holding it.
      boost::thread::sleep(xsecs(1*BaseSeconds));
      boost::thread tw2(thread_adapter<SM>(plain_exclusive, &e2, mtx));

      // Reader one launches, "clearly" after writer two, and "clearly"
      //   while writer 1 still holds the lock
      boost::thread::sleep(xsecs(1*BaseSeconds));
      boost::thread thr1(thread_adapter<SM>(plain_shared,&s1, mtx));
      boost::thread thr2(thread_adapter<SM>(plain_shared,&s2, mtx));

      thr2.join();
      thr1.join();
      tw2.join();
      tw1.join();

      //We can only assure that the writer will be first
      BOOST_INTERPROCES_CHECK(e1.m_value == 10);
      //A that we will execute all
      BOOST_INTERPROCES_CHECK(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20);
   }

   {
      shared_val = 0;
      SM mtx;

      data<SM> s1(1, 3);
      data<SM> s2(2, 3);
      data<SM> e1(1);
      data<SM> e2(2);

      //We launch 2 readers, that will block for 3*BaseTime seconds
      boost::thread thr1(thread_adapter<SM>(plain_shared,&s1, mtx));
      boost::thread thr2(thread_adapter<SM>(plain_shared,&s2, mtx));

      //Make sure they try to hold the sharable lock
      boost::thread::sleep(xsecs(1*BaseSeconds));

      // We launch two writers, that should block until the readers end
      boost::thread tw1(thread_adapter<SM>(plain_exclusive,&e1, mtx));
      boost::thread tw2(thread_adapter<SM>(plain_exclusive,&e2, mtx));

      thr2.join();
      thr1.join();
      tw2.join();
      tw1.join();

      //We can only assure that the shared will finish first...
      BOOST_INTERPROCES_CHECK(s1.m_value == 0 || s2.m_value == 0);
      //...and writers will be mutually excluded after readers
      BOOST_INTERPROCES_CHECK((e1.m_value == 10 && e2.m_value == 20) ||
             (e1.m_value == 20 && e2.m_value == 10) );
   }
}
void test_plain_sharable_mutex()
{
   {
      shared_val = 0;
      SM m1, m2, m3, m4;
      SM *pm1, *pm2, *pm3, *pm4;

      if(SameObject){
         pm1 = pm2 = pm3 = pm4 = &m1;
      }
      else{
         pm1 = &m1;
         pm2 = &m2;
         pm3 = &m3;
         pm4 = &m4;
      }
      data<SM> s1(1);
      data<SM> s2(2);
      data<SM> e1(1);
      data<SM> e2(2);

      // Writer one launches, holds the lock for 3*BaseSeconds seconds.
      boost::thread tw1(thread_adapter<SM>(plain_exclusive, &e1, *pm1));

      // Writer two launches, tries to grab the lock, "clearly"
      //  after Writer one will already be holding it.
      boost::thread::sleep(xsecs(1*BaseSeconds));
      boost::thread tw2(thread_adapter<SM>(plain_exclusive, &e2, *pm2));

      // Reader one launches, "clearly" after writer two, and "clearly"
      //   while writer 1 still holds the lock
      boost::thread::sleep(xsecs(1*BaseSeconds));
      boost::thread thr1(thread_adapter<SM>(plain_shared,&s1, *pm3));
      boost::thread thr2(thread_adapter<SM>(plain_shared,&s2, *pm4));

      thr2.join();
      thr1.join();
      tw2.join();
      tw1.join();

      //We can only assure that the writer will be first
      assert(e1.m_value == 10);
      //A that we will execute all
      assert(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20);
   }

   {
      shared_val = 0;
      SM m1, m2, m3, m4;
      SM *pm1, *pm2, *pm3, *pm4;

      if(SameObject){
         pm1 = pm2 = pm3 = pm4 = &m1;
      }
      else{
         pm1 = &m1;
         pm2 = &m2;
         pm3 = &m3;
         pm4 = &m4;
      }
      data<SM> s1(1, 3);
      data<SM> s2(2, 3);
      data<SM> e1(1);
      data<SM> e2(2);

      //We launch 2 readers, that will block for 3*BaseTime seconds
      boost::thread thr1(thread_adapter<SM>(plain_shared,&s1,*pm1));
      boost::thread thr2(thread_adapter<SM>(plain_shared,&s2,*pm2));

      //Make sure they try to hold the sharable lock
      boost::thread::sleep(xsecs(1*BaseSeconds));

      // We launch two writers, that should block until the readers end
      boost::thread tw1(thread_adapter<SM>(plain_exclusive,&e1,*pm3));
      boost::thread tw2(thread_adapter<SM>(plain_exclusive,&e2,*pm4));

      thr2.join();
      thr1.join();
      tw2.join();
      tw1.join();

      //We can only assure that the shared will finish first...
      assert(s1.m_value == 0 || s2.m_value == 0);
      //...and writers will be mutually excluded after readers
      assert((e1.m_value == 10 && e2.m_value == 20) || 
             (e1.m_value == 20 && e2.m_value == 10) );
   }
}