Reference documentation for deal.II version 9.1.0-pre
thread_management.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/thread_management.h>
17 
18 #include <atomic>
19 #include <cstdlib>
20 #include <iostream>
21 
22 #ifdef DEAL_II_HAVE_UNISTD_H
23 # include <unistd.h>
24 #endif
25 
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 
30 namespace Threads
31 {
32  namespace internal
33  {
34  static std::atomic<unsigned int> n_existing_threads_counter(1);
35 
36 
37  void
38  register_thread()
39  {
40  ++n_existing_threads_counter;
41  }
42 
43 
44 
45  void
46  deregister_thread()
47  {
48  --n_existing_threads_counter;
49  Assert(n_existing_threads_counter >= 1, ExcInternalError());
50  }
51 
52 
53 
54  [[noreturn]] void
55  handle_std_exception(const std::exception &exc) {
56  // lock the following context
57  // to ensure that we don't
58  // print things over each other
59  // if we have trouble from
60  // multiple threads. release
61  // the lock before calling
62  // std::abort, though
63  static Mutex mutex;
64  {
65  Mutex::ScopedLock lock(mutex);
66 
67  std::cerr
68  << std::endl
69  << std::endl
70  << "---------------------------------------------------------"
71  << std::endl
72  << "In one of the sub-threads of this program, an exception\n"
73  << "was thrown and not caught. Since exceptions do not\n"
74  << "propagate to the main thread, the library has caught it.\n"
75  << "The information carried by this exception is given below.\n"
76  << std::endl
77  << "---------------------------------------------------------"
78  << std::endl;
79  std::cerr << "Exception message: " << std::endl
80  << " " << exc.what() << std::endl
81  << "Exception type: " << std::endl
82  << " " << typeid(exc).name() << std::endl;
83  std::cerr << "Aborting!" << std::endl
84  << "---------------------------------------------------------"
85  << std::endl;
86  }
87 
88  std::abort();
89  }
90 
91 
92 
93  [[noreturn]] void handle_unknown_exception()
94  {
95  // lock the following context
96  // to ensure that we don't
97  // print things over each other
98  // if we have trouble from
99  // multiple threads. release
100  // the lock before calling
101  // std::abort, though
102  static Mutex mutex;
103  {
104  Mutex::ScopedLock lock(mutex);
105 
106  std::cerr
107  << std::endl
108  << std::endl
109  << "---------------------------------------------------------"
110  << std::endl
111  << "In one of the sub-threads of this program, an exception\n"
112  << "was thrown and not caught. Since exceptions do not\n"
113  << "propagate to the main thread, the library has caught it.\n"
114  << std::endl
115  << "---------------------------------------------------------"
116  << std::endl;
117  std::cerr << "Type of exception is unknown, but not std::exception.\n"
118  << "No additional information is available.\n"
119  << "---------------------------------------------------------"
120  << std::endl;
121  }
122  std::abort();
123  }
124  } // namespace internal
125 
126 
127 
128  unsigned int
130  {
131  return internal::n_existing_threads_counter;
132  }
133 
134 
135  unsigned int
137  {
138 #ifdef SYS_gettid
139  const pid_t this_id = syscall(SYS_gettid);
140 #elif defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_GETPID)
141  const pid_t this_id = getpid();
142 #else
143  const unsigned int this_id = 0;
144 #endif
145 
146  return static_cast<unsigned int>(this_id);
147  }
148 
149 
150 
151 #ifndef DEAL_II_WITH_THREADS
152  DummyBarrier::DummyBarrier(const unsigned int count, const char *, void *)
153  {
154  (void)count;
155  Assert(count == 1, ExcBarrierSizeNotUseful(count));
156  }
157 
158 
159 #else
160 # ifdef DEAL_II_USE_MT_POSIX
161 
162 
163 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
164  PosixThreadBarrier::PosixThreadBarrier(const unsigned int count,
165  const char *,
166  void *)
167  {
168  pthread_barrier_init(&barrier, nullptr, count);
169  }
170 
171 # else
172 
173  PosixThreadBarrier::PosixThreadBarrier(const unsigned int count,
174  const char *,
175  void *)
176  : count(count)
177  {
178  // throw an exception unless we
179  // have the special case that a
180  // count of 1 is given, since
181  // then waiting for a barrier is
182  // a no-op, and we don't need the
183  // POSIX functionality
184  AssertThrow(count == 1,
185  ExcMessage("Your local POSIX installation does not support\n"
186  "POSIX barriers. You will not be able to use\n"
187  "this class, but the rest of the threading\n"
188  "functionality is available."));
189  }
190 # endif
191 
192 
193 
195  {
196 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
197  pthread_barrier_destroy(&barrier);
198 # else
199  // unless the barrier is a no-op,
200  // complain again (how did we get
201  // here then?)
202  if (count != 1)
203  std::abort();
204 # endif
205  }
206 
207 
208 
209  int
211  {
212 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
213  return pthread_barrier_wait(&barrier);
214 # else
215  // in the special case, this
216  // function is a no-op. otherwise
217  // complain about the missing
218  // POSIX functions
219  if (count == 1)
220  return 0;
221  else
222  {
223  std::abort();
224  return 1;
225  };
226 # endif
227  }
228 
229 
230 
231 # endif
232 #endif
233 
234 
235 
236  std::vector<std::pair<unsigned int, unsigned int>>
237  split_interval(const unsigned int begin,
238  const unsigned int end,
239  const unsigned int n_intervals)
240  {
241  Assert(end >= begin, ExcInternalError());
242 
243  const unsigned int n_elements = end - begin;
244  const unsigned int n_elements_per_interval = n_elements / n_intervals;
245  const unsigned int residual = n_elements % n_intervals;
246 
247  std::vector<std::pair<unsigned int, unsigned int>> return_values(
248  n_intervals);
249 
250  return_values[0].first = begin;
251  for (unsigned int i = 0; i < n_intervals; ++i)
252  {
253  if (i != n_intervals - 1)
254  {
255  return_values[i].second =
256  (return_values[i].first + n_elements_per_interval);
257  // distribute residual in
258  // division equally among
259  // the first few
260  // subintervals
261  if (i < residual)
262  ++return_values[i].second;
263  return_values[i + 1].first = return_values[i].second;
264  }
265  else
266  return_values[i].second = end;
267  };
268  return return_values;
269  }
270 } // namespace Threads
271 
272 
273 DEAL_II_NAMESPACE_CLOSE
unsigned int this_thread_id()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
std::vector< std::pair< unsigned int, unsigned int > > split_interval(const unsigned int begin, const unsigned int end, const unsigned int n_intervals)
static::ExceptionBase & ExcMessage(std::string arg1)
DummyBarrier(const unsigned int count, const char *name=nullptr, void *arg=nullptr)
#define Assert(cond, exc)
Definition: exceptions.h:1227
unsigned int n_existing_threads()
PosixThreadBarrier(const unsigned int count, const char *name=nullptr, void *arg=nullptr)
static::ExceptionBase & ExcInternalError()