// bslmt_mutex.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BSLMT_MUTEX #define INCLUDED_BSLMT_MUTEX #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a platform-independent mutex. // //@CLASSES: // bslmt::Mutex: platform-independent mutex // //@SEE_ALSO: bslmt_recursivemutex, 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(); //.. #include <bslscm_version.h> #include <bslmt_muteximpl_pthread.h> #include <bslmt_muteximpl_win32.h> #include <bslmt_platform.h> namespace BloombergLP { namespace bslmt { template <class THREAD_POLICY> class MutexImpl; // =========== // class Mutex // =========== class Mutex { // This 'class' implements a lightweight, portable wrapper of an OS-level // mutex lock to support intra-process synchronization. The behavior is // undefined if the 'lock' method of this class is invoked more than once // on the same mutex object in the same thread without an intervening call // to 'unLock'. // DATA MutexImpl<Platform::ThreadPolicy> d_imp; // platform-specific // implementation // NOT IMPLEMENTED Mutex(const Mutex&); Mutex& operator=(const Mutex&); public: // PUBLIC TYPES typedef MutexImpl<Platform::ThreadPolicy>::NativeType NativeType; // 'NativeType' is an alias for the underlying OS-level mutex type. It // is exposed so that other 'bslmt' components can operate directly on // this mutex. // CREATORS Mutex(); // Create a mutex object in the unlocked state. ~Mutex(); // Destroy this mutex object. The behavior is undefined if the mutex // is in a locked state. // MANIPULATORS void lock(); // Acquire a lock on this mutex object. If this object is currently // locked by a different thread, then suspend execution of the current // thread until a lock can be acquired. The behavior is undefined if // the calling thread already owns the lock on this mutex, and may // result in deadlock. NativeType& nativeMutex(); // Return a reference to the modifiable OS-level mutex underlying this // object. This method is intended only to support other 'bslmt' // components that must operate directly on this mutex. int tryLock(); // Attempt to acquire a lock on this mutex object. Return 0 on // success, and a non-zero value if this object is already locked by a // different thread. The behavior is undefined if the calling thread // already owns the lock on this mutex, and may result in deadlock. void unlock(); // Release a lock on this mutex that was previously acquired through a // call to 'lock', or a successful call to 'tryLock', enabling another // thread to acquire a lock on this mutex. The behavior is undefined // unless the calling thread currently owns the lock on this mutex. }; } // close package namespace // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ----------- // class Mutex // ----------- // CREATORS inline bslmt::Mutex::Mutex() { } inline bslmt::Mutex::~Mutex() { } // MANIPULATORS inline void bslmt::Mutex::lock() { d_imp.lock(); } inline bslmt::Mutex::NativeType& bslmt::Mutex::nativeMutex() { return d_imp.nativeMutex(); } inline int bslmt::Mutex::tryLock() { return d_imp.tryLock(); } inline void bslmt::Mutex::unlock() { d_imp.unlock(); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------