fiber/test/test_mutex_dispatch.cpp
2017-06-08 23:22:08 +02:00

448 lines
14 KiB
C++

// Copyright Oliver Kowalke 2013.
// 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)
//
// This test is based on the tests of Boost.Thread
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <map>
#include <mutex>
#include <stdexcept>
#include <vector>
#include <boost/test/unit_test.hpp>
#include <boost/fiber/all.hpp>
typedef std::chrono::nanoseconds ns;
typedef std::chrono::milliseconds ms;
int value1 = 0;
int value2 = 0;
template< typename M >
void fn1( M & mtx) {
typedef M mutex_type;
typename std::unique_lock< mutex_type > lk( mtx);
++value1;
for ( int i = 0; i < 3; ++i)
boost::this_fiber::yield();
}
template< typename M >
void fn2( M & mtx) {
typedef M mutex_type;
++value2;
typename std::unique_lock< mutex_type > lk( mtx);
++value2;
}
void fn3( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
m.lock();
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
}
void fn4( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
while ( ! m.try_lock() );
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
}
void fn5( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK( m.try_lock_for(ms(300)+ms(2000)) == true);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
}
void fn6( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_for(ms(250)) == false);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
}
void fn7( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5ms
}
void fn8( boost::fibers::timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
ns d = t1 - t0 - ms(250);
ns r = ns(5000000)+ms(2000); // within 6ms
BOOST_CHECK(d < r); // within 6ms
}
void fn9( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
m.lock();
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.lock();
m.unlock();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms
}
void fn10( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
while (!m.try_lock()) ;
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock());
m.unlock();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ms(50000)+ms(2000)); // within 50 ms
}
void fn11( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_for(ms(300)+ms(1000)) == true);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock());
m.unlock();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
}
void fn12( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_for(ms(250)) == false);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ms(5000)+ms(2000)); // within 5 ms
}
void fn13( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(300) + ms(1000)) == true);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
}
void fn14( boost::fibers::recursive_timed_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock_until(std::chrono::steady_clock::now() + ms(250)) == false);
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(5000000)+ms(2000)); // within 5 ms
}
void fn15( boost::fibers::recursive_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
m.lock();
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.lock();
m.unlock();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(2500000)+ms(2000)); // within 2.5 ms
}
void fn16( boost::fibers::recursive_mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
while (!m.try_lock());
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
BOOST_CHECK(m.try_lock());
m.unlock();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
}
void fn17( boost::fibers::mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
m.lock();
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ms(2500)+ms(2000)); // within 2.5 ms
}
void fn18( boost::fibers::mutex & m) {
std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now();
while (!m.try_lock()) ;
std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now();
m.unlock();
ns d = t1 - t0 - ms(250);
BOOST_CHECK(d < ns(50000000)+ms(2000)); // within 50 ms
}
template< typename M >
struct test_lock {
typedef M mutex_type;
typedef typename std::unique_lock< M > lock_type;
void operator()() {
mutex_type mtx;
// Test the lock's constructors.
{
lock_type lk(mtx, std::defer_lock);
BOOST_CHECK(!lk);
}
lock_type lk(mtx);
BOOST_CHECK(lk ? true : false);
// Test the lock and unlock methods.
lk.unlock();
BOOST_CHECK(!lk);
lk.lock();
BOOST_CHECK(lk ? true : false);
}
};
template< typename M >
struct test_exclusive {
typedef M mutex_type;
typedef typename std::unique_lock< M > lock_type;
void operator()() {
value1 = 0;
value2 = 0;
BOOST_CHECK_EQUAL( 0, value1);
BOOST_CHECK_EQUAL( 0, value2);
mutex_type mtx;
boost::fibers::fiber f1( boost::fibers::launch::dispatch, & fn1< mutex_type >, std::ref( mtx) );
boost::fibers::fiber f2( boost::fibers::launch::dispatch, & fn2< mutex_type >, std::ref( mtx) );
BOOST_ASSERT( f1.joinable() );
BOOST_ASSERT( f2.joinable() );
f1.join();
f2.join();
BOOST_CHECK_EQUAL( 1, value1);
BOOST_CHECK_EQUAL( 2, value2);
}
};
template< typename M >
struct test_recursive_lock {
typedef M mutex_type;
typedef typename std::unique_lock< M > lock_type;
void operator()() {
mutex_type mx;
lock_type lock1(mx);
lock_type lock2(mx);
}
};
void do_test_mutex() {
test_lock< boost::fibers::mutex >()();
test_exclusive< boost::fibers::mutex >()();
{
boost::fibers::mutex mtx;
mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn17, std::ref( mtx) );
boost::this_fiber::sleep_for( ms(250) );
mtx.unlock();
f.join();
}
{
boost::fibers::mutex mtx;
mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn18, std::ref( mtx) );
boost::this_fiber::sleep_for( ms(250) );
mtx.unlock();
f.join();
}
}
void test_mutex() {
boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_mutex).join();
}
void do_test_recursive_mutex() {
test_lock< boost::fibers::recursive_mutex >()();
test_exclusive< boost::fibers::recursive_mutex >()();
test_recursive_lock< boost::fibers::recursive_mutex >()();
{
boost::fibers::recursive_mutex mtx;
mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn15, std::ref( mtx) );
boost::this_fiber::sleep_for( ms(250) );
mtx.unlock();
f.join();
}
{
boost::fibers::recursive_mutex mtx;
mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn16, std::ref( mtx) );
boost::this_fiber::sleep_for( ms(250) );
mtx.unlock();
f.join();
}
}
void test_recursive_mutex() {
boost::fibers::fiber( boost::fibers::launch::dispatch, do_test_recursive_mutex).join();
}
void do_test_timed_mutex() {
test_lock< boost::fibers::timed_mutex >()();
test_exclusive< boost::fibers::timed_mutex >()();
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn3, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn4, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn5, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn6, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(300) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn7, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn8, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(300) + ms(1000) );
timed_mtx.unlock();
f.join();
}
}
void test_timed_mutex() {
boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_timed_mutex).join();
}
void do_test_recursive_timed_mutex() {
test_lock< boost::fibers::recursive_timed_mutex >()();
test_exclusive< boost::fibers::recursive_timed_mutex >()();
test_recursive_lock< boost::fibers::recursive_timed_mutex >()();
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn9, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn10, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn11, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn12, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(400) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn13, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(250) );
timed_mtx.unlock();
f.join();
}
{
boost::fibers::recursive_timed_mutex timed_mtx;
timed_mtx.lock();
boost::fibers::fiber f( boost::fibers::launch::dispatch, & fn14, std::ref( timed_mtx) );
boost::this_fiber::sleep_for( ms(300) );
timed_mtx.unlock();
f.join();
}
}
void test_recursive_timed_mutex() {
boost::fibers::fiber( boost::fibers::launch::dispatch, & do_test_recursive_timed_mutex).join();
}
boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
boost::unit_test::test_suite * test =
BOOST_TEST_SUITE("Boost.Fiber: mutex test suite");
test->add( BOOST_TEST_CASE( & test_mutex) );
test->add( BOOST_TEST_CASE( & test_recursive_mutex) );
test->add( BOOST_TEST_CASE( & test_timed_mutex) );
test->add( BOOST_TEST_CASE( & test_recursive_timed_mutex) );
return test;
}