|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2006-10-24 19:36:45
Peter Dimov wrote:
> Chris Thomasson wrote:
>> "Peter Dimov" <pdimov_at_[hidden]> wrote in message
>> news:001801c6f7bd$c32f62a0$6607a8c0_at_pdimov2...
>>> Chris Thomasson wrote:
>>>
>>>> How does the original algorithm compare to yours?
>>>
>>> I haven't tried it yet. Will do.
>>
>> Humm...
>
> Hmmm. Doesn't seem to work.
Works now.
The performance is somewhat better than my other semaphore-based attempts in
most common scenarios. But it still doesn't beat the "naive" implementation
at
http://pdimov.com/cpp/rw_mutex.cpp
Here's the entire header:
#ifndef BOOST_DETAIL_RW_MUTEX_HPP_INCLUDED
#define BOOST_DETAIL_RW_MUTEX_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
// Copyright (c) 2005 Chris Thomasson
// Copyright (c) 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)
#include <boost/detail/interlocked.hpp>
#include <cassert>
#include <windows.h>
bool dwcas( void * d, void * c, const void * x )
{
long ov = *(long*)c;
long nv = BOOST_INTERLOCKED_COMPARE_EXCHANGE( (long*)d, *(long const*)x,
ov );
if( ov == nv )
{
return false;
}
else
{
*(long*)c = nv;
return true;
}
}
class rw_mutex
{
private:
rw_mutex( rw_mutex const & );
rw_mutex & operator=( rw_mutex const & );
private:
struct state
{
unsigned reads: 10;
unsigned writes: 2;
unsigned r_waits: 10;
unsigned w_waits: 10;
};
state mtx_;
HANDLE sema_r_;
HANDLE sema_w_;
public:
rw_mutex()
{
state st = { 0 };
mtx_ = st;
sema_r_ = CreateSemaphore( 0, 0, 1023, 0 );
sema_w_ = CreateSemaphore( 0, 0, 1023, 0 );
}
~rw_mutex()
{
CloseHandle( sema_r_ );
CloseHandle( sema_w_ );
}
void rdlock()
{
for( ;; )
{
state cmp = mtx_, xchg;
do
{
xchg = cmp;
if( !cmp.writes && !cmp.w_waits )
{
++xchg.reads;
}
else
{
++xchg.r_waits;
}
}
while( dwcas( &mtx_, &cmp, &xchg ) );
if( !cmp.writes && !cmp.w_waits )
{
break;
}
WaitForSingleObject( sema_r_, INFINITE );
}
}
void lock()
{
for ( ;; )
{
state cmp = mtx_, xchg;
do
{
xchg = cmp;
if( !cmp.reads && !cmp.writes )
{
++xchg.writes;
}
else
{
++xchg.w_waits;
}
}
while( dwcas( &mtx_, &cmp, &xchg ) );
if ( !cmp.reads && !cmp.writes )
{
break;
}
WaitForSingleObject( sema_w_, INFINITE );
}
}
void unlock()
{
state cmp = mtx_, xchg;
do
{
assert( cmp.writes == 1 );
assert( cmp.reads == 0 );
xchg = cmp;
--xchg.writes;
if( cmp.w_waits )
{
--xchg.w_waits;
}
else if( cmp.r_waits )
{
xchg.r_waits = 0;
}
}
while( dwcas( &mtx_, &cmp, &xchg ) );
if( cmp.w_waits )
{
ReleaseSemaphore( sema_w_, 1, 0 );
}
else if( cmp.r_waits )
{
ReleaseSemaphore( sema_r_, cmp.r_waits, 0 );
}
}
void rdunlock()
{
state cmp = mtx_, xchg;
do
{
assert( cmp.writes == 0 );
assert( cmp.reads > 0 );
xchg = cmp;
--xchg.reads;
if( !xchg.reads && cmp.w_waits )
{
--xchg.w_waits;
}
else if( cmp.r_waits )
{
xchg.r_waits = 0;
}
}
while( dwcas( &mtx_, &cmp, &xchg ) );
if ( !xchg.reads && cmp.w_waits )
{
ReleaseSemaphore( sema_w_, 1, 0 );
}
else if ( cmp.r_waits )
{
ReleaseSemaphore( sema_r_, cmp.r_waits, 0 );
}
}
public:
// lock classes
class scoped_read_lock
{
private:
rw_mutex & mx_;
scoped_read_lock( scoped_read_lock const & );
scoped_read_lock & operator=( scoped_read_lock const & );
public:
scoped_read_lock( rw_mutex & mx ): mx_( mx )
{
mx_.rdlock();
}
~scoped_read_lock()
{
mx_.rdunlock();
}
};
class scoped_write_lock
{
private:
rw_mutex & mx_;
scoped_write_lock( scoped_write_lock const & );
scoped_write_lock & operator=( scoped_write_lock const & );
public:
scoped_write_lock( rw_mutex & mx ): mx_( mx )
{
mx_.lock();
}
~scoped_write_lock()
{
mx_.unlock();
}
};
};
#endif // #ifndef BOOST_DETAIL_RW_MUTEX_HPP_INCLUDED
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk