// bsls_bsllock.h -*-C++-*- #ifndef INCLUDED_BSLS_BSLLOCK #define INCLUDED_BSLS_BSLLOCK #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a platform-independent mutex for use below 'bslmt'. // //@CLASSES: // bsls::BslLock: platform-independent mutex // bsls::BslLockGuard: RAII mechanism for locking/unlocking a 'BslLock' // //@SEE_ALSO: bslmt_mutex // //@DESCRIPTION: This component provides a mutually exclusive lock primitive // ("mutex") by wrapping a suitable platform-specific mechanism. The // 'bsls::BslLock' class provides 'lock' and 'unlock' operations. Note that // 'bsls::BslLock' is not intended for direct client use; see 'bslmt_mutex' // instead. Also note that 'bsls::BslLock' is not recursive. // // This component also provides the 'bsls::BslLockGuard' class, a mechanism // that follows the RAII idiom for automatically acquiring and releasing the // lock on an associated 'bsls::BslLock' object. To ensure exception safety, // client code should make use of a 'bsls::BslLockGuard' object wherever // appropriate rather than calling the methods on the associated // 'bsls::BslLock' object directly. // ///Usage ///----- // In this section we show intended use of this component. // ///Example 1: Using 'bsls::BslLock' to Make a 'class' Thread-Safe /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // In this example we illustrate the use of 'bsls::BslLock' and // 'bsls::BslLockGuard' to write a thread-safe class. // // First, we provide an elided definition of the 'my_Account' class. Note the // 'd_lock' data member of type 'bsls::BslLock': //.. // class my_Account { // // This 'class' implements a very simplistic bank account. It is meant // // for illustrative purposes only. // // // DATA // double d_money; // amount of money in the account // mutable bsls::BslLock d_lock; // ensure exclusive access to 'd_money' // // // ... // // public: // // // ... // // // MANIPULATORS // void deposit(double amount); // // Atomically deposit the specified 'amount' of money into this // // account. The behavior is undefined unless 'amount >= 0.0'. // // int withdraw(double amount); // // Atomically withdraw the specified 'amount' of money from this // // account. Return 0 on success, and a non-zero value otherwise. // // The behavior is undefined unless 'amount >= 0.0'. // // // ... // }; //.. // Next, we show the implementation of the two 'my_Account' manipulators // show-casing the use of 'bsls::BslLock' and 'bsls::BslLockGuard': //.. // // MANIPULATORS // void my_Account::deposit(double amount) // { //.. // Here, we use the interface of 'bsls::BslLock' directly. However, wherever // appropriate, a 'bsls::BslLockGuard' object should be used instead to ensure // that an acquired lock is always properly released, even if an exception is // thrown: //.. // d_lock.lock(); // consider using 'bsls::BslLockGuard' (see 'withdraw') // d_money += amount; // d_lock.unlock(); // } //.. // In contrast, 'withdraw' uses a 'bsls::BslLockGuard' to automatically acquire // and release the lock. The lock is acquired as a side-effect of the // construction of 'guard', and released when 'guard' is destroyed upon // returning from the function: //.. // int my_Account::withdraw(double amount) // { // bsls::BslLockGuard guard(&d_lock); // a very good practice // // if (amount <= d_money) { // d_money -= amount; // return 0; // } // else { // return -1; // } // } //.. #include <bsls_platform.h> #ifdef BSLS_PLATFORM_OS_WINDOWS #include <bsls_bsllockimpl_win32.h> #else #include <bsls_bsllockimpl_pthread.h> #endif #ifdef BDE_BUILD_TARGET_SAFE // This component needs to be below bsls_assert in the physical hierarchy, so // 'BSLS_ASSERT' macros can't be used here. To workaround this issue, we use // the C 'assert' instead. #include <assert.h> #define BSLS_BSLLOCK_ASSERT_SAFE(x) assert((x)) #else #define BSLS_BSLLOCK_ASSERT_SAFE(x) #endif namespace BloombergLP { namespace bsls { // ============= // class BslLock // ============= class BslLock { // This 'class' implements a light-weight, portable wrapper of an OS-level // mutex to support intra-process synchronization. The mutex implemented // by this class is *non*-recursive. Note that 'BslLock' is *not* intended // for direct use by client code; it is meant for internal use only. // DATA #ifdef BSLS_PLATFORM_OS_WINDOWS BslLockImpl_win32 d_lock; // Windows critical section #else BslLockImpl_pthread d_lock; // 'pthreads' mutex object #endif private: // NOT IMPLEMENTED BslLock(const BslLock&); // = delete BslLock& operator=(const BslLock&); // = delete public: // CREATORS BslLock(); // Create a lock object initialized to the unlocked state. ~BslLock(); // Destroy this lock object. The behavior is undefined unless this // object is in the unlocked state. // MANIPULATORS void lock(); // Acquire the lock on this object. If the lock on this object is // currently held by another thread, then suspend execution of the // calling thread until the lock can be acquired. The behavior is // undefined unless the calling thread does not already hold the lock // on this object. Note that deadlock may result if this method is // invoked while the calling thread holds the lock on the object. void unlock(); // Release the lock on this object that was previously acquired through // a call to 'lock', enabling another thread to acquire the lock. The // behavior is undefined unless the calling thread holds the lock on // this object. }; // ================== // class BslLockGuard // ================== class BslLockGuard { // This 'class' implements a guard for automatically acquiring and // releasing the lock on an associated 'bsls::BslLock' object. This // mechanism follows the RAII idiom whereby the lock on the 'BslLock' // associated with a guard object is acquired upon construction and // released upon destruction. // DATA BslLock *d_lock_p; // lock guarded by this object (held, not owned) private: // NOT IMPLEMENTED BslLockGuard(const BslLockGuard&); // = delete BslLockGuard& operator=(const BslLockGuard&); // = delete public: // CREATORS explicit BslLockGuard(BslLock *lock); // Create a guard object that conditionally manages the specified // 'lock', and acquires the lock on 'lock' by invoking its 'lock' // method. The behavior is undefined unless the calling thread does // not already hold the lock on 'lock'. Note that deadlock may result // if a guard is created for 'lock' while the calling thread holds the // lock on 'lock'. Also note that 'lock' must remain valid throughout // the lifetime of this guard, or until 'release' is called. ~BslLockGuard(); // Destroy this guard object and release the lock on the object it // manages (if any) by invoking the 'unlock' method of the object that // was supplied at construction of this guard. If no lock is currently // being managed, this method has no effect. Note that if this guard // object currently manages a lock, this method assumes the behavior of // 'BslLock::unlock'. // MANIPULATORS void release(); // Release from management, with no effect, the object currently // managed by this guard, if any. Note that 'unlock' is *not* called // on the managed object upon its release. }; // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ------------- // class BslLock // ------------- // CREATORS inline BslLock::BslLock() { } inline BslLock::~BslLock() { } // MANIPULATORS inline void BslLock::lock() { d_lock.lock(); } inline void BslLock::unlock() { d_lock.unlock(); } // ------------------ // class BslLockGuard // ------------------ // CREATORS inline BslLockGuard::BslLockGuard(BslLock *lock) : d_lock_p(lock) { BSLS_BSLLOCK_ASSERT_SAFE(lock); d_lock_p->lock(); } inline BslLockGuard::~BslLockGuard() { if (d_lock_p) { d_lock_p->unlock(); } } // MANIPULATORS inline void BslLockGuard::release() { d_lock_p = 0; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 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 ----------------------------------