BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmt_readerwritermutex

Detailed Description

Outline

Purpose

Provide a multi-reader/single-writer lock.

Classes

See also
bslmt_readerwriterlock, bslmt_readlockguard, bslmt_writelockguard, bslmt_readerwriterlockassert

Description

This component defines an efficient multi-reader/single-writer lock mechanism, bslmt::ReaderWriterMutex. It is designed to allow concurrent read access to a shared resource while still controlling write access.

Reader-writer locks are generally used for resources that are frequently read and less frequently updated. Unlike other lock mechanisms (e.g., "mutexes"), reader-writer locks provide two distinct but mutually exclusive lock states: a read lock state, and a write lock state.

To the extent the implementation's underlying mutex prevents a thread from starving, readers can not be starved by writers and writers can not be starved by readers. If the underlying mutex, to some extent, favors re-acquisition of the mutex to allowing a new thread to obtain the mutex (e.g., the mutex obtained on Linux), this reader-writer lock is writer biased since writers can re-acquire the lock in the presence of readers but readers will not be able to re-acquire the lock in the presence of writers.

bslmt ReadWrite Locking Components

Note that for extremely short hold times and very high concurrency, a bslmt::Mutex might outperform all of the above.

Usage

This section illustrates intended use of this component.

Example 1: Maintaining an Account Balance

The following snippets of code illustrate the use of bslmt::ReaderWriterMutex to write a thread-safe class, my_Account. Note the typical use of mutable for the lock:

// This `class` represents a bank account with a single balance.
class my_Account {
// DATA
bsls::Types::Uint64 d_pennies; // amount of money in the
// account
mutable bslmt::ReaderWriterMutex d_lock; // guard access to
// `d_account_p`
public:
// CREATORS
/// Create an account with zero balance.
my_Account();
/// Create an account having the value of the specified `original`
/// account.
my_Account(const my_Account& original);
/// Destroy this account.
~my_Account();
// MANIPULATORS
/// Atomically assign to this account the value of the specified
/// `rhs` account, and return a reference to this modifiable
/// account. Note that this operation is thread-safe; no `lock` is
/// needed.
my_Account& operator=(const my_Account& rhs);
/// Atomically deposit the specified `pennies` into this account.
/// Note that this operation is thread-safe; no `lock` is needed.
void deposit(bsls::Types::Uint64 pennies);
/// Attempt to atomically withdraw the specified `pennies` from this
/// account. Return 0 on success and update this account to reflect
/// the withdrawal. Otherwise, return a non-zero value and do not
/// update the balance of this account. Note that this operation is
/// thread-safe; no `lock` is needed.
int withdraw(bsls::Types::Uint64 pennies);
// ACCESSORS
/// Atomically return the number of pennies that are available for
/// withdrawal from this account.
bsls::Types::Uint64 balanceInPennies() const;
};
// CREATORS
my_Account::my_Account()
: d_pennies(0)
{
}
my_Account::my_Account(const my_Account& original)
: d_pennies(original.balanceInPennies())
{
}
my_Account::~my_Account()
{
}
// MANIPULATORS
my_Account& my_Account::operator=(const my_Account& rhs)
{
Definition bslmt_readerwritermutex.h:244
unsigned long long Uint64
Definition bsls_types.h:137

Where appropriate, clients should use a lock-guard to ensure that an acquired mutex is always properly released, even if an exception is thrown.

d_lock.lockWrite();
d_pennies = rhs.balanceInPennies();
d_lock.unlockWrite();
return *this;
}
void my_Account::deposit(bsls::Types::Uint64 pennies)
{
d_lock.lockWrite();
d_pennies += pennies;
d_lock.unlockWrite();
}
int my_Account::withdraw(bsls::Types::Uint64 pennies)
{
int rv = 0;
d_lock.lockWrite();
if (pennies <= d_pennies) {
d_pennies -= pennies;
}
else {
rv = 1;
}
d_lock.unlockWrite();
return rv;
}
// ACCESSORS
bsls::Types::Uint64 my_Account::balanceInPennies() const
{
d_lock.lockRead();
bsls::Types::Uint64 rv = d_pennies;
d_lock.unlockRead();
return rv;
}

The atomic my_Account methods are used as expected:

my_Account account;
account.deposit(10050);
assert(10050 == account.balanceInPennies());
bsls::Types::Uint64 paycheckInPennies = 5025;
account.deposit(paycheckInPennies);
assert(15075 == account.balanceInPennies());