Reference documentation for deal.II version Git f40be01994 2020-04-09 07:13:12 +0200
\(\newcommand{\vcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\vcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
thread_management.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2000 - 2019 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 #ifdef DEAL_II_USE_MT_POSIX
152 
153 
154 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
155  PosixThreadBarrier::PosixThreadBarrier(const unsigned int count,
156  const char *,
157  void *)
158  {
159  pthread_barrier_init(&barrier, nullptr, count);
160  }
161 
162 # else
163 
164  PosixThreadBarrier::PosixThreadBarrier(const unsigned int count,
165  const char *,
166  void *)
167  : count(count)
168  {
169  // throw an exception unless we
170  // have the special case that a
171  // count of 1 is given, since
172  // then waiting for a barrier is
173  // a no-op, and we don't need the
174  // POSIX functionality
175  AssertThrow(count == 1,
176  ExcMessage("Your local POSIX installation does not support\n"
177  "POSIX barriers. You will not be able to use\n"
178  "this class, but the rest of the threading\n"
179  "functionality is available."));
180  }
181 # endif
182 
183 
184 
186  {
187 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
188  pthread_barrier_destroy(&barrier);
189 # else
190  // unless the barrier is a no-op,
191  // complain again (how did we get
192  // here then?)
193  if (count != 1)
194  std::abort();
195 # endif
196  }
197 
198 
199 
200  int
202  {
203 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS
204  return pthread_barrier_wait(&barrier);
205 # else
206  // in the special case, this
207  // function is a no-op. otherwise
208  // complain about the missing
209  // POSIX functions
210  if (count == 1)
211  return 0;
212  else
213  {
214  std::abort();
215  return 1;
216  }
217 # endif
218  }
219 
220 
221 
222 #endif
223 
224 
225 
226  std::vector<std::pair<unsigned int, unsigned int>>
227  split_interval(const unsigned int begin,
228  const unsigned int end,
229  const unsigned int n_intervals)
230  {
231  Assert(end >= begin, ExcInternalError());
232 
233  const unsigned int n_elements = end - begin;
234  const unsigned int n_elements_per_interval = n_elements / n_intervals;
235  const unsigned int residual = n_elements % n_intervals;
236 
237  std::vector<std::pair<unsigned int, unsigned int>> return_values(
238  n_intervals);
239 
240  return_values[0].first = begin;
241  for (unsigned int i = 0; i < n_intervals; ++i)
242  {
243  if (i != n_intervals - 1)
244  {
245  return_values[i].second =
246  (return_values[i].first + n_elements_per_interval);
247  // distribute residual in
248  // division equally among
249  // the first few
250  // subintervals
251  if (i < residual)
252  ++return_values[i].second;
253  return_values[i + 1].first = return_values[i].second;
254  }
255  else
256  return_values[i].second = end;
257  }
258  return return_values;
259  }
260 } // namespace Threads
261 
262 
263 DEAL_II_NAMESPACE_CLOSE
unsigned int this_thread_id()
#define AssertThrow(cond, exc)
Definition: exceptions.h:1531
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)
#define Assert(cond, exc)
Definition: exceptions.h:1419
unsigned int n_existing_threads()
std::lock_guard< std::mutex > ScopedLock
PosixThreadBarrier(const unsigned int count, const char *name=nullptr, void *arg=nullptr)
static ::ExceptionBase & ExcInternalError()