|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2006-10-26 16:19:16
>> (This redundant wakeup may not be visible in a benchmark, but it
>> can steal CPU from other busy non-contending threads in a real
>> application.)
To test this, I added "free" threads to the benchmark. These compete on a
different mutex. With my latest experiment, this reveals odd/intriguing
patterns of the form
2R+4W+0F: 29
2R+4W+4F: 18
The additional four free threads improve performance!
Test code:
// Copyright (c) 2005, 2006 Peter Dimov
//
// 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)
#undef NDEBUG
#include "rw_mutex_.hpp"
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <iostream>
#include <ctime>
int const N = 1048576;
int const n = 1000; // vector size
rw_mutex mtx;
std::vector<int> v( n );
boost::mutex mx2;
std::vector<int> v2( n );
boost::mutex cmx;
//
void reader( int r )
{
for( int i = 0; i < N; ++i )
{
rw_mutex::scoped_read_lock lock( mtx );
int m = v.front();
for( std::vector<int>::const_iterator j = v.begin(), end = v.end();
j != end; ++j )
{
assert( *j == m );
}
if( i == N / 4 || i == N / 2 || i == N / 2 + N / 4 )
{
boost::mutex::scoped_lock lock( cmx );
std::cout << " r" << r;
}
}
boost::mutex::scoped_lock lock( cmx );
std::cout << " R" << r;
}
void writer( int w )
{
for( int i = 0; i < N; ++i )
{
rw_mutex::scoped_write_lock lock( mtx );
int m = v.front();
for( std::vector<int>::iterator j = v.begin(), end = v.end(); j !=
end; ++j )
{
++*j;
assert( *j == m + 1 );
}
if( i == N / 4 || i == N / 2 || i == N / 2 + N / 4 )
{
boost::mutex::scoped_lock lock( cmx );
std::cout << " w" << w;
}
}
boost::mutex::scoped_lock lock( cmx );
std::cout << " W" << w;
}
void free_( int f )
{
for( int i = 0; i < N; ++i )
{
boost::mutex::scoped_lock lock( mx2 );
int m = v2.front();
for( std::vector<int>::iterator j = v2.begin(), end = v2.end(); j !=
end; ++j )
{
++*j;
assert( *j == m + 1 );
}
if( i == N / 4 || i == N / 2 || i == N / 2 + N / 4 )
{
boost::mutex::scoped_lock lock( cmx );
std::cout << " f" << f;
}
}
boost::mutex::scoped_lock lock( cmx );
std::cout << " F" << f;
}
void test( int nr, int nw, int nf )
{
try
{
std::cout << nr << "R + " << nw << "W + " << nf << "F:";
std::time_t tm = std::time( 0 );
boost::thread_group group;
for( int i = 0; i < nr || i < nw || i < nf; ++i )
{
if( i < nw )
{
group.create_thread( boost::bind( writer, i ) );
}
if( i < nr )
{
group.create_thread( boost::bind( reader, i ) );
}
if( i < nf )
{
group.create_thread( boost::bind( free_, i ) );
}
}
group.join_all();
std::cout << ": " << std::time( 0 ) - tm << std::endl;
//for( int i = 0; i < 6; ++i )
//{
// std::cout << mtx.retries( i ) << ' ';
//}
std::cout << std::endl;
}
catch( std::exception const & x )
{
std::cout << x.what() << std::endl;
}
}
int main()
{
test( 0, 1, 0 );
test( 0, 1, 1 );
test( 0, 4, 0 );
test( 0, 4, 4 );
test( 1, 0, 0 );
test( 1, 0, 1 );
test( 1, 1, 0 );
test( 1, 1, 1 );
test( 1, 4, 0 );
test( 1, 4, 4 );
test( 2, 0, 0 );
test( 2, 0, 2 );
test( 2, 1, 0 );
test( 2, 1, 1 );
test( 2, 2, 0 );
test( 2, 2, 2 );
test( 2, 4, 0 );
test( 2, 4, 4 );
test( 4, 0, 0 );
test( 4, 0, 4 );
test( 4, 1, 0 );
test( 4, 1, 1 );
test( 4, 1, 4 );
test( 4, 4, 0 );
test( 4, 4, 4 );
test( 16, 0, 0 );
test( 16, 0, 4 );
test( 16, 1, 0 );
test( 16, 1, 1 );
test( 16, 1, 4 );
test( 16, 4, 0 );
test( 16, 4, 4 );
//test( 64, 0 );
//test( 64, 1 );
//test( 64, 4 );
}
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk