Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bslmt_mutex
[Package bslmt]

Provide a platform-independent mutex. More...

Namespaces

namespace  bslmt

Detailed Description

Outline
Purpose:
Provide a platform-independent mutex.
Classes:
bslmt::Mutex platform-independent mutex
See also:
Component bslmt_recursivemutex, Component bslmt_mutex
Description:
This component provides a mutually exclusive lock primitive ("mutex") by wrapping a suitable platform-specific mechanism. The bslmt::Mutex class provides the following operations: lock, tryLock, and unlock.
The behavior is undefined if unlock is invoked on a bslmt::Mutex object from a thread that did not successfully acquire the lock, or if lock is called twice in a thread without calling unlock in between (i.e., bslmt::Mutex is non-recursive). In particular, lock may or may not deadlock if the current thread holds the lock.
Usage:
The following snippets of code illustrate the use of bslmt::Mutex to write a thread-safe class, my_SafeAccount, given a thread-unsafe class, my_Account. The simple my_Account class is defined as follows:
  class my_Account {
      // This 'class' represents a bank account with a single balance.  It
      // is not thread-safe.

      // DATA
      double d_money;  // amount of money in the account

    public:
      // CREATORS
      my_Account();
          // Create an account with zero balance.

      my_Account(const my_Account& original);
          // Create an account having the value of the specified 'original'
          // account.

      ~my_Account();
          // Destroy this account.

      // MANIPULATORS
      my_Account& operator=(const my_Account& rhs);
          // Assign to this account the value of the specified 'rhs' account,
          // and return a reference to this modifiable account.

      void deposit(double amount);
          // Deposit the specified 'amount' of money into this account.

      void withdraw(double amount);
          // Withdraw the specified 'amount' of money from this account.

      // ACCESSORS
      double balance() const;
          // Return the amount of money that is available for withdrawal
          // from this account.
  };

  // CREATORS
  my_Account::my_Account()
  : d_money(0.0)
  {
  }

  my_Account::my_Account(const my_Account& original)
  : d_money(original.d_money)
  {
  }

  my_Account::~my_Account()
  {
  }

  // MANIPULATORS
  my_Account& my_Account::operator=(const my_Account& rhs)
  {
      d_money = rhs.d_money;
      return *this;
  }

  void my_Account::deposit(double amount)
  {
      d_money += amount;
  }

  void my_Account::withdraw(double amount)
  {
      d_money -= amount;
  }

  // ACCESSORS
  double my_Account::balance() const
  {
      return d_money;
  }
Next, we use a bslmt::Mutex object to render atomic the function calls of a new thread-safe class that uses the thread-unsafe class in its implementation. Note the typical use of mutable for the lock:
  class my_SafeAccountHandle {
      // This 'class' provides a thread-safe handle to an account (held, not
      // owned) passed at construction.

      // DATA
      my_Account          *d_account_p;  // held, not owned
      mutable bslmt::Mutex  d_lock;       // guard access to 'd_account_p'

      // NOT IMPLEMENTED
      my_SafeAccountHandle(const my_SafeAccountHandle&);
      my_SafeAccountHandle& operator=(const my_SafeAccountHandle&);

    public:
      // CREATORS
      my_SafeAccountHandle(my_Account *account);
          // Create a thread-safe handle to the specified 'account'.

      ~my_SafeAccountHandle();
          // Destroy this handle.  Note that the held account is unaffected
          // by this operation.

      // MANIPULATORS
      void deposit(double amount);
          // Atomically deposit the specified 'amount' of money into the
          // account held by this handle.  Note that this operation is
          // thread-safe; no 'lock' is needed.

      void lock();
          // Provide exclusive access to the underlying account held by this
          // object.

      void unlock();
          // Release exclusivity of the access to the underlying account held
          // by this object.

      void withdraw(double amount);
          // Atomically withdraw the specified 'amount' of money from the
          // account held by this handle.  Note that this operation is
          // thread-safe; no 'lock' is needed.

      // ACCESSORS
      my_Account *account() const;
          // Return the address of the modifiable account held by this
          // handle.

      double balance() const;
          // Atomically return the amount of money that is available for
          // withdrawal from the account held by this handle.
  };
The implementation show-casing the use of bslmt::Mutex follows:
  // CREATORS
  my_SafeAccountHandle::my_SafeAccountHandle(my_Account *account)
  : d_account_p(account)
  {
  }

  my_SafeAccountHandle::~my_SafeAccountHandle()
  {
  }

  // MANIPULATORS
  void my_SafeAccountHandle::deposit(double amount)
  {
Where appropriate, clients should use a lock-guard to ensure that an acquired mutex is always properly released, even if an exception is thrown. See bslmt_lockguard for more information:
      d_lock.lock();  // consider using 'bslmt::LockGuard'
      d_account_p->deposit(amount);
      d_lock.unlock();
  }

  void my_SafeAccountHandle::lock()
  {
      d_lock.lock();
  }

  void my_SafeAccountHandle::unlock()
  {
      d_lock.unlock();
  }

  void my_SafeAccountHandle::withdraw(double amount)
  {
      d_lock.lock();  // consider using 'bslmt::LockGuard'
      d_account_p->withdraw(amount);
      d_lock.unlock();
  }

  // ACCESSORS
  my_Account *my_SafeAccountHandle::account() const
  {
      return d_account_p;
  }

  double my_SafeAccountHandle::balance() const
  {
      d_lock.lock();  // consider using 'bslmt::LockGuard'
      const double res = d_account_p->balance();
      d_lock.unlock();
      return res;
  }
The handle's atomic methods are used just as the corresponding methods in my_Account:
  my_Account account;
  account.deposit(100.50);
  double paycheck = 50.25;
  my_SafeAccountHandle handle(&account);

                             assert(100.50 == handle.balance());
  handle.deposit(paycheck);  assert(150.75 == handle.balance());
We can also use the handle's lock and unlock methods to implement non-primitive atomic transactions on the account:
  double check[5] = { 25.0, 100.0, 99.95, 75.0, 50.0 };

  handle.lock();  // consider using 'bslmt::LockGuard'

  double originalBalance = handle.account()->balance();
  for (int i = 0; i < 5; ++i) {
      handle.account()->deposit(check[i]);
  }
  assert(originalBalance + 349.95 == handle.account()->balance());
  handle.unlock();