Reference documentation for deal.II version 9.0.0
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 at
12 // the top level of the deal.II distribution.
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 register_thread ()
38  {
39  ++n_existing_threads_counter;
40  }
41 
42 
43 
44  void deregister_thread ()
45  {
46  --n_existing_threads_counter;
47  Assert (n_existing_threads_counter >= 1,
49  }
50 
51 
52 
53  [[noreturn]]
54  void handle_std_exception (const std::exception &exc)
55  {
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 << std::endl << std::endl
68  << "---------------------------------------------------------"
69  << std::endl
70  << "In one of the sub-threads of this program, an exception\n"
71  << "was thrown and not caught. Since exceptions do not\n"
72  << "propagate to the main thread, the library has caught it.\n"
73  << "The information carried by this exception is given below.\n"
74  << std::endl
75  << "---------------------------------------------------------"
76  << std::endl;
77  std::cerr << "Exception message: " << std::endl
78  << " " << exc.what() << std::endl
79  << "Exception type: " << std::endl
80  << " " << typeid(exc).name() << std::endl;
81  std::cerr << "Aborting!" << std::endl
82  << "---------------------------------------------------------"
83  << std::endl;
84  }
85 
86  std::abort ();
87  }
88 
89 
90 
91  [[noreturn]]
92  void handle_unknown_exception ()
93  {
94  // lock the following context
95  // to ensure that we don't
96  // print things over each other
97  // if we have trouble from
98  // multiple threads. release
99  // the lock before calling
100  // std::abort, though
101  static Mutex mutex;
102  {
103  Mutex::ScopedLock lock(mutex);
104 
105  std::cerr << std::endl << std::endl
106  << "---------------------------------------------------------"
107  << std::endl
108  << "In one of the sub-threads of this program, an exception\n"
109  << "was thrown and not caught. Since exceptions do not\n"
110  << "propagate to the main thread, the library has caught it.\n"
111  << std::endl
112  << "---------------------------------------------------------"
113  << std::endl;
114  std::cerr << "Type of exception is unknown, but not std::exception.\n"
115  << "No additional information is available.\n"
116  << "---------------------------------------------------------"
117  << std::endl;
118  }
119  std::abort ();
120  }
121  }
122 
123 
124 
125  unsigned int n_existing_threads ()
126  {
127  return internal::n_existing_threads_counter;
128  }
129 
130 
131  unsigned int this_thread_id ()
132  {
133 #ifdef SYS_gettid
134  const pid_t this_id = syscall(SYS_gettid);
135 #elif defined(DEAL_II_HAVE_UNISTD_H) && defined(DEAL_II_HAVE_GETPID)
136  const pid_t this_id = getpid();
137 #else
138  const unsigned int this_id = 0;
139 #endif
140 
141  return static_cast<unsigned int>(this_id);
142  }
143 
144 
145 
146 #ifndef DEAL_II_WITH_THREADS
147  DummyBarrier::DummyBarrier (const unsigned int count,
148  const char *,
149  void *)
150  {
151  (void)count;
152  Assert (count == 1, ExcBarrierSizeNotUseful(count));
153  }
154 
155 
156 #else
157 # ifdef DEAL_II_USE_MT_POSIX
158 
159 
160 #ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
161  PosixThreadBarrier::PosixThreadBarrier (const unsigned int count,
162  const char *,
163  void *)
164  {
165  pthread_barrier_init (&barrier, nullptr, count);
166  }
167 
168 #else
169 
170  PosixThreadBarrier::PosixThreadBarrier (const unsigned int count,
171  const char *,
172  void *)
173  : count (count)
174  {
175  // throw an exception unless we
176  // have the special case that a
177  // count of 1 is given, since
178  // then waiting for a barrier is
179  // a no-op, and we don't need the
180  // POSIX functionality
181  AssertThrow (count == 1,
182  ExcMessage ("Your local POSIX installation does not support\n"
183  "POSIX barriers. You will not be able to use\n"
184  "this class, but the rest of the threading\n"
185  "functionality is available."));
186  }
187 #endif
188 
189 
190 
192  {
193 #ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
194  pthread_barrier_destroy (&barrier);
195 #else
196  // unless the barrier is a no-op,
197  // complain again (how did we get
198  // here then?)
199  if (count != 1)
200  std::abort ();
201 #endif
202  }
203 
204 
205 
206  int
208  {
209 #ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
210  return pthread_barrier_wait (&barrier);
211 #else
212  // in the special case, this
213  // function is a no-op. otherwise
214  // complain about the missing
215  // POSIX functions
216  if (count == 1)
217  return 0;
218  else
219  {
220  std::abort ();
221  return 1;
222  };
223 #endif
224  }
225 
226 
227 
228 
229 # endif
230 #endif
231 
232 
233 
234  std::vector<std::pair<unsigned int,unsigned int> >
235  split_interval (const unsigned int begin,
236  const unsigned int end,
237  const unsigned int n_intervals)
238  {
239  Assert (end >= begin, ExcInternalError());
240 
241  const unsigned int n_elements = end-begin;
242  const unsigned int n_elements_per_interval = n_elements / n_intervals;
243  const unsigned int residual = n_elements % n_intervals;
244 
245  std::vector<std::pair<unsigned int,unsigned int> > return_values (n_intervals);
246 
247  return_values[0].first = begin;
248  for (unsigned int i=0; i<n_intervals; ++i)
249  {
250  if (i != n_intervals-1)
251  {
252  return_values[i].second = (return_values[i].first
253  + n_elements_per_interval);
254  // distribute residual in
255  // division equally among
256  // the first few
257  // subintervals
258  if (i < residual)
259  ++return_values[i].second;
260  return_values[i+1].first = return_values[i].second;
261  }
262  else
263  return_values[i].second = end;
264  };
265  return return_values;
266  }
267 } // end namespace Thread
268 
269 
270 DEAL_II_NAMESPACE_CLOSE
unsigned int this_thread_id()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
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:1142
unsigned int n_existing_threads()
PosixThreadBarrier(const unsigned int count, const char *name=nullptr, void *arg=nullptr)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcBarrierSizeNotUseful(int arg1)