// bslmt_threadgroup.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_THREADGROUP #define INCLUDED_BSLMT_THREADGROUP #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a container for managing a group of threads. // //@CLASSES: // bslmt::ThreadGroup: A container that manages a group of threads. // //@SEE_ALSO: bslmt_threadutil, bslmt_threadattributes // //@DESCRIPTION: This component provides a simple mechanism for managing a group // of threads. The group is represented by an instance of the // 'bslmt::ThreadGroup' class. To use this component, the client code calls // 'addThread', providing a function to be executed. The specified function is // executed in a new thread managed by the thread group (note that 'addThread' // is thread-safe). The 'joinAll' call blocks until all threads in the group // have finished executing. // ///Thread Safety ///------------- // This component is thread-safe and thread-enabled, meaning that multiple // threads may safely use their own instances or a shared instance of a // 'bslmt::ThreadGroup' object. // ///Usage ///----- // The following usage example illustrates how 'bslmt::ThreadGroup' might be // used in a typical test driver to simplify the execution of a common function // in multiple threads. Suppose that we are interested in creating a // stress-test for the 'bslmt::Mutex' class. The test is controlled by two // parameters: the number of executions (defined by subsequent calls to 'lock' // and 'unlock', and the amount of contention, defined by the number of threads // accessing the mutex. The test can be expressed as two functions. The first // is executed in each thread via a functor object: //.. // class MutexTestJob { // int d_numIterations; // int *d_value_p; // bslmt::Mutex *d_mutex_p; // // public: // MutexTestJob(int numIterations, int *value, bslmt::Mutex *mutex) // : d_numIterations(numIterations) // , d_value_p(value) // , d_mutex_p(mutex) // {} // // void operator()() { // for (int i = 0; i < d_numIterations; ++i) { // bslmt::LockGuard<bslmt::Mutex> guard(d_mutex_p); // ++*d_value_p; // } // } // }; //.. // The second executes the main body of the test: //.. // bslma::TestAllocator ta; // { // const int NUM_ITERATIONS = 10000; // const int NUM_THREADS = 8; // // bslmt::Mutex mutex; // object under test // int value = 0; // // MutexTestJob testJob(NUM_ITERATIONS, &value, &mutex); // // bslmt::ThreadGroup threadGroup(&ta); // for (int i = 0; i < NUM_THREADS; ++i) { // assert(0 == threadGroup.addThread(testJob)); // } // threadGroup.joinAll(); // assert(NUM_ITERATIONS * NUM_THREADS == value); // } // assert(0 < ta.numAllocations()); // assert(0 == ta.numBytesInUse()); //.. #include <bslscm_version.h> #include <bslmt_mutex.h> #include <bslmt_threadattributes.h> #include <bslmt_threadutil.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bsls_assert.h> #include <bsls_atomic.h> #include <bsl_vector.h> namespace BloombergLP { namespace bslmt { // ================= // class ThreadGroup // ================= class ThreadGroup { // This class provides a simple mechanism for managing a group of joinable // threads. The destructor ensures that any running threads are detached // so that resources are not leaked. This class is thread-enabled, // thread-safe, and exception-neutral. // PRIVATE TYPES typedef bsl::vector<ThreadUtil::Handle> ThreadContainer; // INSTANCE DATA bsls::AtomicInt d_numThreads; ThreadContainer d_threads; Mutex d_threadsMutex; // PRIVATE MANIPULATORS void addThread(const ThreadUtil::Handle& handle); // Add the specified 'handle' to the 'd_threads' container. If an // exception is thrown, 'handle' will be released. private: // not implemented ThreadGroup(const ThreadGroup&); ThreadGroup& operator=(const ThreadGroup&); public: // CREATORS explicit ThreadGroup(bslma::Allocator *basicAllocator = 0); // Create an empty thread group. Optionally specify 'basicAllocator' // will be used to supply memory. If 'basicAllocator' is 0, the // currently installed default allocator will be used. ~ThreadGroup(); // Destroy this object. Any threads not joined will be allowed to run // independently, and will no longer be joinable. // MANIPULATORS template <class INVOKABLE> int addThread(const INVOKABLE& functor); template <class INVOKABLE> int addThread(const INVOKABLE& functor, const ThreadAttributes& attributes); // Begin executing the specified invokable 'functor' in a new thread, // using the optionally specified thread 'attributes'. Return 0 on // success, and a non-zero value otherwise. 'INVOKABLE' shall be a // copy-constructible type having the equivalent of // 'void operator()()'. Note that threads are always created joinable, // regardless of the mode specified in 'attributes'. template <class INVOKABLE> int addThreads(const INVOKABLE& functor, int numThreads); template <class INVOKABLE> int addThreads(const INVOKABLE& functor, int numThreads, const ThreadAttributes& attributes); // Begin executing the specified invokable 'functor' in the specified // new 'numThreads', using the optionally specified thread // 'attributes'. Return 'numThreads' on success, or the number of // threads successfully started otherwise. 'INVOKABLE' shall be a // copy-constructible type having the equivalent of // 'void operator()()'. Note that threads are always created joinable, // regardless of the mode specified in 'attributes'. void joinAll(); // Block the calling thread until all threads started in this group // have finished executing. // ACCESSORS int numThreads() const; // Return a snapshot of the number of threads started in this group // that have not been joined. }; } // close package namespace // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ----------------- // class ThreadGroup // ----------------- // MANIPULATORS template<class INVOKABLE> inline int bslmt::ThreadGroup::addThread(const INVOKABLE& functor) { return addThread(functor, ThreadAttributes()); } template<class INVOKABLE> inline int bslmt::ThreadGroup::addThreads(const INVOKABLE& functor, int numThreads) { return addThreads(functor, numThreads, ThreadAttributes()); } template<class INVOKABLE> int bslmt::ThreadGroup::addThread(const INVOKABLE& functor, const ThreadAttributes& attributes) { ThreadUtil::Handle handle; int rc = 1; if (ThreadAttributes::e_CREATE_JOINABLE != attributes.detachedState()) { ThreadAttributes newAttributes(attributes); newAttributes.setDetachedState(ThreadAttributes::e_CREATE_JOINABLE); rc = ThreadUtil::createWithAllocator( &handle, newAttributes, functor, d_threads.get_allocator().mechanism()); } else { rc = ThreadUtil::createWithAllocator( &handle, attributes, functor, d_threads.get_allocator().mechanism()); } if (0 == rc) { addThread(handle); } return rc; } template<class INVOKABLE> int bslmt::ThreadGroup::addThreads(const INVOKABLE& functor, int numThreads, const ThreadAttributes& attributes) { BSLS_ASSERT(0 <= numThreads); int numAdded; for (numAdded = 0; numAdded < numThreads; ++numAdded) { if (0 != addThread(functor, attributes)) { break; } } return numAdded; } // ACCESSORS inline int bslmt::ThreadGroup::numThreads() const { return d_numThreads.loadRelaxed(); } // ============================================================================ // TYPE TRAITS // ============================================================================ namespace bslma { template <> struct UsesBslmaAllocator<bslmt::ThreadGroup> : bsl::true_type {}; } // close namespace bslma } // 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 ----------------------------------