libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
fixed_threads_container.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_PRIVATE_FIXED_THREADS_CONTAINER_HPP
2 #define LIBJMMCG_CORE_PRIVATE_FIXED_THREADS_CONTAINER_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2012 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include "../../core/config.h"
23 #include "../../core/trace.hpp"
24 
25 #include <algorithm>
26 #include <cassert>
27 #include <memory>
28 #include <unordered_map>
29 
30 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace ppd { namespace private_ {
31 
32 /// This is a low-level collection of pool_thread objects, that is created by one other thread.
33 /**
34  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.
35 
36  \see pool_thread
37 */
38 template<
39  class PTT,
40  class ThrdT
41 >
44 
45 public:
46  using pool_traits_type=PTT;
47  using os_traits=typename pool_traits_type::os_traits;
48  using thread_traits=typename os_traits::thread_traits;
50  typename thread_traits::api_params_type::tid_type, ///< Note that this should be a perfect hash.
52  >;
55  using key_type=typename container_type::key_type;
56  using iterator=typename container_type::iterator;
61 
62  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) {
63  pool.reserve(sz);
64  lookup_table.reserve(sz);
65  lookup_table.rehash(sz);
66  for (size_type i=0; i<sz; ++i) {
67  pool.emplace_back(std::ref(exit_requested), std::ref(signalled_work_queue));
68  auto a_thread=std::next(pool.begin(), pool.size()-1);
69  a_thread->create_running();
70  typename thread_traits::api_params_type::processor_mask_type mask(i);
71  try {
72  a_thread->kernel_affinity(mask);
73  } catch (typename thread_type::exception_type const &ex) {
74  // It's not a nightmare if we can't set the affinity.
75  }
76  const auto tid=a_thread->params().id;
77  lookup_table.insert(typename container_type::value_type(tid, a_thread));
78  }
79  assert(pool.size()==lookup_table.size());
80  assert(size()==sz);
81  }
82 
83  fixed_pool_of_threads(size_type const sz, exit_requested_type &exit_requested) noexcept(false) {
84  pool.reserve(sz);
85  lookup_table.reserve(sz);
86  lookup_table.rehash(sz);
87  for (size_type i=0; i<sz; ++i) {
88  pool.emplace_back(std::ref(exit_requested));
89  auto a_thread=std::next(pool.begin(), pool.size()-1);
90  a_thread->create_running();
91  typename thread_traits::api_params_type::processor_mask_type mask(i);
92  try {
93  a_thread->kernel_affinity(mask);
94  } catch (typename thread_type::exception_type const &ex) {
95  // It's not a nightmare if we can't set the affinity.
96  }
97  const auto tid=a_thread->params().id;
98  lookup_table.insert(typename container_type::value_type(tid, a_thread));
99  }
100  assert(pool.size()==lookup_table.size());
101  assert(size()==sz);
102  }
103 
108 
109  thread_type const &first_thread() const noexcept(true) FORCE_INLINE {
110  return *pool.begin();
111  }
113  return *pool.begin();
114  }
115 
116  const_iterator end() const noexcept(true) FORCE_INLINE {
117  return lookup_table.end();
118  }
119 
120  const_iterator find(key_type key) const noexcept(true) {
121  return lookup_table.find(key);
122  }
123 
125  return lookup_table.find(key);
126  }
127 
128  bool __fastcall empty() const noexcept(true) FORCE_INLINE {
129  assert(lookup_table.empty()==pool.empty());
130  return pool.empty();
131  }
132 
133  size_type __fastcall size() const noexcept(true) FORCE_INLINE {
134  const size_type sz=lookup_table.size();
135  [[maybe_unused]] const size_type currently_running=num_running();
136  assert(sz>=currently_running);
137  return sz;
138  }
139 
140  void clear() noexcept(false) FORCE_INLINE {
141  // Note that there may be inactive threads in the infinite threads pool, that haven't yet been purged.
142  assert(lookup_table.size()>=num_running());
143  lookup_table.clear();
144  pool.clear();
145  }
146 
147 private:
148  template<class S> friend
150  template<class S> friend
152  internal_container_type pool;
153  container_type lookup_table;
154 
155  internal_container_type const &__fastcall colln() const noexcept(true) FORCE_INLINE {
156  return pool;
157  }
158 
159  size_type num_running() const noexcept(true) FORCE_INLINE {
160  assert(pool.size()==lookup_table.size());
161  return std::accumulate(
162  pool.begin(),
163  pool.end(),
164  size_type(),
165  [](size_type const s, typename internal_container_type::const_iterator::value_type const &v) {
166  return s+static_cast<size_type>(v.is_running());
167  }
168  );
169  }
170 };
171 
172 } } } }
173 
174 #endif