root/core/private_/fixed_threads_container.hpp

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. first_thread
  2. first_thread
  3. end
  4. find
  5. find
  6. empty
  7. clear
  8. colln
  9. num_running

   1 #ifndef libjmmcg_core_private_fixed_threads_container_hpp
   2 #define libjmmcg_core_private_fixed_threads_container_hpp
   3 
   4 /******************************************************************************
   5 ** $Header: svn+ssh://jmmcg@svn.code.sf.net/p/libjmmcg/code/trunk/libjmmcg/core/private_/fixed_threads_container.hpp 2353 2018-10-21 20:22:18Z jmmcg $
   6 **
   7 ** Copyright © 2012 by J.M.McGuiness, coder@hussar.me.uk
   8 **
   9 ** This library is free software; you can redistribute it and/or
  10 ** modify it under the terms of the GNU Lesser General Public
  11 ** License as published by the Free Software Foundation; either
  12 ** version 2.1 of the License, or (at your option) any later version.
  13 **
  14 ** This library is distributed in the hope that it will be useful,
  15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17 ** Lesser General Public License for more details.
  18 **
  19 ** You should have received a copy of the GNU Lesser General Public
  20 ** License along with this library; if not, write to the Free Software
  21 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22 */
  23 
  24 #include "../../core/non_copyable.hpp"
  25 #include "../../core/trace.hpp"
  26 
  27 #include <algorithm>
  28 #include <cassert>
  29 #include <memory>
  30 #include <unordered_map>
  31 
  32 namespace jmmcg { namespace ppd { namespace private_ {
  33 
  34 /// This is a low-level collection of pool_thread objects, that is created by one other thread.
  35 /**
  36         This class is a bit crafty: it creates two collections: one to contain the pool_threads, the other a hash map into that pool, to speed looking up into the pool. The former pool carefully in-place constructs the pool_threads, so that their layout is orderly, hopefully mimicing the architectural layout of cores. hence enhancing cache locality, etc.
  37 
  38         \see pool_thread
  39 */
  40 template<
  41         class PTT,
  42         class ThrdT
  43 >
  44 class fixed_pool_of_threads {
  45         using internal_container_type=std::vector<ThrdT>;
  46 
  47 public:
  48         using pool_traits_type=PTT;
  49         using os_traits=typename pool_traits_type::os_traits;
  50         using thread_traits=typename os_traits::thread_traits;
  51         using container_type=std::unordered_map<
  52                 typename thread_traits::api_params_type::tid_type,      ///< Note that this should be a perfect hash.
  53                 typename internal_container_type::iterator
  54         >;
  55         using thread_type=typename internal_container_type::value_type;
  56         using value_type=thread_type;
  57         using key_type=typename container_type::key_type;
  58         using iterator=typename container_type::iterator;
  59         using const_iterator=typename container_type::const_iterator;
  60         using size_type=typename container_type::size_type;
  61         using exit_requested_type=typename PTT::template pool_thread_queue_details<typename thread_type::queue_model>::exit_requested_type;
  62         using have_work_type=typename PTT::template pool_thread_queue_details<typename thread_type::queue_model>::have_work_type;
  63 
  64         fixed_pool_of_threads(size_type const sz, exit_requested_type &exit_requested, typename internal_container_type::value_type::signalled_work_queue_type &signalled_work_queue) noexcept(false) {
  65                 pool.reserve(sz);
  66                 lookup_table.reserve(sz);
  67                 lookup_table.rehash(sz);
  68                 for (size_type i=0; i<sz; ++i) {
  69                         pool.emplace_back(std::ref(exit_requested), std::ref(signalled_work_queue));
  70                         auto a_thread=std::next(pool.begin(), pool.size()-1);
  71                         a_thread->create_running();
  72                         typename thread_traits::api_params_type::processor_mask_type mask(i);
  73                         try {
  74                                 a_thread->kernel_affinity(mask);
  75                         } catch (typename thread_type::exception_type const &ex) {
  76                                 // It's not a nightmare if we can't set the affinity.
  77 // TODO                         JMMCG_TRACE(_T("Minor error detected: ")<<ex);
  78                         }
  79                         const auto tid=a_thread->params().id;
  80                         lookup_table.insert(typename container_type::value_type(tid, a_thread));
  81                 }
  82                 assert(pool.size()==lookup_table.size());
  83                 assert(size()==sz);
  84         }
  85 
  86         fixed_pool_of_threads(size_type const sz, exit_requested_type &exit_requested) noexcept(false) {
  87                 pool.reserve(sz);
  88                 lookup_table.reserve(sz);
  89                 lookup_table.rehash(sz);
  90                 for (size_type i=0; i<sz; ++i) {
  91                         pool.emplace_back(std::ref(exit_requested));
  92                         auto a_thread=std::next(pool.begin(), pool.size()-1);
  93                         a_thread->create_running();
  94                         typename thread_traits::api_params_type::processor_mask_type mask(i);
  95                         try {
  96                                 a_thread->kernel_affinity(mask);
  97                         } catch (typename thread_type::exception_type const &ex) {
  98                                 // It's not a nightmare if we can't set the affinity.
  99 // TODO                         JMMCG_TRACE(_T("Minor error detected: ")<<ex);
 100                         }
 101                         const auto tid=a_thread->params().id;
 102                         lookup_table.insert(typename container_type::value_type(tid, a_thread));
 103                 }
 104                 assert(pool.size()==lookup_table.size());
 105                 assert(size()==sz);
 106         }
 107 
 108         fixed_pool_of_threads(fixed_pool_of_threads const &)=delete;
 109         fixed_pool_of_threads &operator=(fixed_pool_of_threads const &)=delete;
 110         fixed_pool_of_threads(fixed_pool_of_threads &&)=default;
 111         fixed_pool_of_threads &operator=(fixed_pool_of_threads &&)=default;
 112 
 113         thread_type const &first_thread() const noexcept(true) FORCE_INLINE {
 114                 return *pool.begin();
 115         }
 116         thread_type &first_thread() noexcept(true) FORCE_INLINE {
 117                 return *pool.begin();
 118         }
 119 
 120         const_iterator end() const noexcept(true) FORCE_INLINE {
 121                 return lookup_table.end();
 122         }
 123 
 124         const_iterator find(key_type key) const noexcept(true) {
 125                 return lookup_table.find(key);
 126         }
 127 
 128         iterator find(key_type key) noexcept(true) FORCE_INLINE {
 129                 return lookup_table.find(key);
 130         }
 131 
 132         bool __fastcall empty() const noexcept(true) FORCE_INLINE {
 133                 assert(lookup_table.empty()==pool.empty());
 134                 return pool.empty();
 135         }
 136 
 137         size_type __fastcall size() const noexcept(true) FORCE_INLINE {
 138                 const size_type sz=lookup_table.size();
 139                 [[maybe_unused]] const size_type currently_running=num_running();
 140                 assert(sz>=currently_running);
 141                 return sz;
 142         }
 143 
 144         void clear() noexcept(false) FORCE_INLINE {
 145                 // Note that there may be inactive threads in the infinite threads pool, that haven't yet been purged.
 146                 assert(lookup_table.size()>=num_running());
 147                 lookup_table.clear();
 148                 pool.clear();
 149         }
 150 
 151 private:
 152         template<class S> friend
 153         class wrkr_accumulate_across_threads;
 154         template<class S> friend
 155         class mstr_accumulate_across_threads;
 156         internal_container_type pool;
 157         container_type lookup_table;
 158 
 159         internal_container_type const &__fastcall colln() const noexcept(true) FORCE_INLINE {
 160                 return pool;
 161         }
 162 
 163         size_type num_running() const noexcept(true) FORCE_INLINE {
 164                 assert(pool.size()==lookup_table.size());
 165                 return std::accumulate(
 166                         pool.begin(),
 167                         pool.end(),
 168                         size_type(),
 169                         [](size_type const s, typename internal_container_type::const_iterator::value_type const &v) {
 170                                 return s+static_cast<size_type>(v.is_running());
 171                         }
 172                 );
 173         }
 174 };
 175 
 176 } } }
 177 
 178 #endif

/* [<][>][^][v][top][bottom][index][help] */