// Copyright (C) 2001-2003 // William E. Kempf // // Permission to use, copy, modify, distribute and sell this software // and its documentation for any purpose is hereby granted without fee, // provided that the above copyright notice appear in all copies and // that both that copyright notice and this permission notice appear // in supporting documentation. William E. Kempf makes no representations // about the suitability of this software for any purpose. // It is provided "as is" without express or implied warranty. ////////////////////////////////////////////////////////////////////////////// // // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // See http://www.boost.org/libs/interprocess for documentation. // ////////////////////////////////////////////////////////////////////////////// #ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER #define BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER #include #include #include #include "boost_interprocess_check.hpp" #include #include #include #include #include #include "util.hpp" namespace boost { namespace interprocess { namespace test { template void plain_exclusive(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm); boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); shared_val += 10; pdata->m_value = shared_val; } template void plain_shared(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::interprocess::sharable_lock l(sm); if(pdata->m_secs){ boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); } pdata->m_value = shared_val; } template void try_exclusive(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::interprocess::scoped_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); shared_val += 10; pdata->m_value = shared_val; } } template void try_shared(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::interprocess::sharable_lock l(sm, boost::interprocess::defer_lock); if (l.try_lock()){ if(pdata->m_secs){ boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); } pdata->m_value = shared_val; } } template void timed_exclusive(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::scoped_lock l (sm, boost::interprocess::defer_lock); if (l.timed_lock(pt)){ boost::interprocess::ipcdetail::thread_sleep((1000*3*BaseSeconds)); shared_val += 10; pdata->m_value = shared_val; } } template void timed_shared(void *arg, SM &sm) { data *pdata = static_cast*>(arg); boost::posix_time::ptime pt(delay(pdata->m_secs)); boost::interprocess::sharable_lock l(sm, boost::interprocess::defer_lock); if (l.timed_lock(pt)){ if(pdata->m_secs){ boost::interprocess::ipcdetail::thread_sleep((1000*pdata->m_secs*BaseSeconds)); } pdata->m_value = shared_val; } } template void test_plain_sharable_mutex() { { shared_val = 0; SM mtx; data s1(1); data s2(2); data e1(1); data e2(2); // Writer one launches, holds the lock for 3*BaseSeconds seconds. boost::interprocess::ipcdetail::OS_thread_t tw1; boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(plain_exclusive, &e1, mtx)); // Writer two launches, tries to grab the lock, "clearly" // after Writer one will already be holding it. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); boost::interprocess::ipcdetail::OS_thread_t tw2; boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(plain_exclusive, &e2, mtx)); // Reader one launches, "clearly" after writer two, and "clearly" // while writer 1 still holds the lock boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); boost::interprocess::ipcdetail::OS_thread_t thr1; boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(plain_shared,&s1, mtx)); boost::interprocess::ipcdetail::OS_thread_t thr2; boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter(plain_shared,&s2, mtx)); boost::interprocess::ipcdetail::thread_join(thr2); boost::interprocess::ipcdetail::thread_join(thr1); boost::interprocess::ipcdetail::thread_join(tw2); boost::interprocess::ipcdetail::thread_join(tw1); //We can only assure that the writer will be first BOOST_INTERPROCESS_CHECK(e1.m_value == 10); //A that we will execute all BOOST_INTERPROCESS_CHECK(s1.m_value == 20 || s2.m_value == 20 || e2.m_value == 20); } { shared_val = 0; SM mtx; data s1(1, 3); data s2(2, 3); data e1(1); data e2(2); //We launch 2 readers, that will block for 3*BaseTime seconds boost::interprocess::ipcdetail::OS_thread_t thr1; boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(plain_shared,&s1, mtx)); boost::interprocess::ipcdetail::OS_thread_t thr2; boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter(plain_shared,&s2, mtx)); //Make sure they try to hold the sharable lock boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); // We launch two writers, that should block until the readers end boost::interprocess::ipcdetail::OS_thread_t tw1; boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(plain_exclusive,&e1, mtx)); boost::interprocess::ipcdetail::OS_thread_t tw2; boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(plain_exclusive,&e2, mtx)); boost::interprocess::ipcdetail::thread_join(thr2); boost::interprocess::ipcdetail::thread_join(thr1); boost::interprocess::ipcdetail::thread_join(tw2); boost::interprocess::ipcdetail::thread_join(tw1); //We can only assure that the shared will finish first... BOOST_INTERPROCESS_CHECK(s1.m_value == 0 || s2.m_value == 0); //...and writers will be mutually excluded after readers BOOST_INTERPROCESS_CHECK((e1.m_value == 10 && e2.m_value == 20) || (e1.m_value == 20 && e2.m_value == 10) ); } } template void test_try_sharable_mutex() { SM mtx; data s1(1); data e1(2); data 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::interprocess::ipcdetail::OS_thread_t tw1; boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(try_exclusive,&e1,mtx)); // Reader one launches, "clearly" after writer #1 holds the lock // and before it releases the lock. boost::interprocess::ipcdetail::thread_sleep((1000*1*BaseSeconds)); boost::interprocess::ipcdetail::OS_thread_t thr1; boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(try_shared,&s1,mtx)); // Writer two launches in the same timeframe. boost::interprocess::ipcdetail::OS_thread_t tw2; boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(try_exclusive,&e2,mtx)); boost::interprocess::ipcdetail::thread_join(tw2); boost::interprocess::ipcdetail::thread_join(thr1); boost::interprocess::ipcdetail::thread_join(tw1); BOOST_INTERPROCESS_CHECK(e1.m_value == 10); BOOST_INTERPROCESS_CHECK(s1.m_value == -1); // Try would return w/o waiting BOOST_INTERPROCESS_CHECK(e2.m_value == -1); // Try would return w/o waiting } template void test_timed_sharable_mutex() { SM mtx; data s1(1,1*BaseSeconds); data s2(2,3*BaseSeconds); data e1(3,3*BaseSeconds); data 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::interprocess::ipcdetail::OS_thread_t tw1; boost::interprocess::ipcdetail::thread_launch(tw1, thread_adapter(timed_exclusive,&e1,mtx)); boost::interprocess::ipcdetail::thread_sleep((1000*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::interprocess::ipcdetail::OS_thread_t tw2; boost::interprocess::ipcdetail::thread_launch(tw2, thread_adapter(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::interprocess::ipcdetail::OS_thread_t thr1; boost::interprocess::ipcdetail::thread_launch(thr1, thread_adapter(timed_shared,&s1,mtx)); boost::interprocess::ipcdetail::OS_thread_t thr2; boost::interprocess::ipcdetail::thread_launch(thr2, thread_adapter(timed_shared,&s2,mtx)); boost::interprocess::ipcdetail::thread_join(tw1); boost::interprocess::ipcdetail::thread_join(thr1); boost::interprocess::ipcdetail::thread_join(thr2); boost::interprocess::ipcdetail::thread_join(tw2); BOOST_INTERPROCESS_CHECK(e1.m_value == 10); BOOST_INTERPROCESS_CHECK(s1.m_value == -1); BOOST_INTERPROCESS_CHECK(s2.m_value == 10); BOOST_INTERPROCESS_CHECK(e2.m_value == -1); } template void test_all_sharable_mutex() { std::cout << "test_plain_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; test_plain_sharable_mutex(); std::cout << "test_try_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; test_try_sharable_mutex(); std::cout << "test_timed_sharable_mutex<" << typeid(SM).name() << ">" << std::endl; test_timed_sharable_mutex(); } }}} //namespace boost { namespace interprocess { namespace test { #include #endif //#ifndef BOOST_INTERPROCESS_TEST_SHARABLE_MUTEX_TEST_TEMPLATE_HEADER