Reference documentation for deal.II version Git cb0bd54b52 2019-09-21 16:31:22 -0400
\(\newcommand{\dealcoloneq}{\mathrel{\vcenter{:}}=}\)
subscriptor.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 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/logstream.h>
17 #include <deal.II/base/subscriptor.h>
18 #include <deal.II/base/thread_management.h>
19 
20 #include <algorithm>
21 #include <iostream>
22 #include <string>
23 #include <typeinfo>
24 
25 DEAL_II_NAMESPACE_OPEN
26 
27 
28 static const char *unknown_subscriber = "unknown subscriber";
29 
30 
31 std::mutex Subscriptor::mutex;
32 
33 
34 Subscriptor::Subscriptor(Subscriptor &&subscriptor) noexcept
35  : counter(0)
36  , object_info(subscriptor.object_info)
37 {
38  for (const auto validity_ptr : subscriptor.validity_pointers)
39  *validity_ptr = false;
40 }
41 
42 
43 
45 {
46  for (const auto validity_ptr : validity_pointers)
47  *validity_ptr = false;
48  object_info = nullptr;
49 }
50 
51 
52 void
54 {
55  // Check whether there are still subscriptions to this object. If so, output
56  // the actual name of the class to which this object belongs, i.e. the most
57  // derived class. Note that the name may be mangled, so it need not be the
58  // clear-text class name. However, you can obtain the latter by running the
59  // c++filt program over the output.
60 #ifdef DEBUG
61 
62  // If there are still active pointers, show a message and kill the program.
63  // However, under some circumstances, this is not so desirable. For example,
64  // in code like this:
65  //
66  // Triangulation tria;
67  // DoFHandler *dh = new DoFHandler(tria);
68  // ...some function that throws an exception
69  //
70  // the exception will lead to the destruction of the triangulation, but since
71  // the dof_handler is on the heap it will not be destroyed. This will trigger
72  // an assertion in the triangulation. If we kill the program at this point, we
73  // will never be able to learn what caused the problem. In this situation,
74  // just display a message and continue the program.
75  if (counter != 0)
76  {
77 # if __cpp_lib_uncaught_exceptions >= 201411
78  // std::uncaught_exception() is deprecated in c++17
79  if (std::uncaught_exceptions() == 0)
80 # else
81  if (std::uncaught_exception() == false)
82 # endif
83  {
84  std::string infostring;
85  for (const auto &map_entry : counter_map)
86  {
87  if (map_entry.second > 0)
88  infostring += std::string("\n from Subscriber ") +
89  std::string(map_entry.first);
90  }
91 
92  if (infostring.empty())
93  infostring = "<none>";
94 
96  ExcInUse(counter.load(),
97  object_info->name(),
98  infostring));
99  }
100  else
101  {
102  std::cerr
103  << "---------------------------------------------------------"
104  << std::endl
105  << "An object pointed to by a SmartPointer is being destroyed."
106  << std::endl
107  << "Under normal circumstances, this would abort the program."
108  << std::endl
109  << "However, another exception is being processed at the"
110  << std::endl
111  << "moment, so the program will continue to run to allow"
112  << std::endl
113  << "this exception to be processed." << std::endl
114  << "---------------------------------------------------------"
115  << std::endl;
116  }
117  }
118 #endif
119 }
120 
121 
122 
123 Subscriptor &
125 {
126  for (const auto validity_ptr : s.validity_pointers)
127  *validity_ptr = false;
128  object_info = s.object_info;
129  return *this;
130 }
131 
132 
133 
134 void
135 Subscriptor::subscribe(std::atomic<bool> *const validity,
136  const std::string & id) const
137 {
138  std::lock_guard<std::mutex> lock(mutex);
139 
140  if (object_info == nullptr)
141  object_info = &typeid(*this);
142  ++counter;
143 
144  const std::string &name = id.empty() ? unknown_subscriber : id;
145 
146  ++counter_map[name];
147 
148  *validity = true;
149  validity_pointers.push_back(validity);
150 }
151 
152 
153 
154 void
155 Subscriptor::unsubscribe(std::atomic<bool> *const validity,
156  const std::string & id) const
157 {
158  const std::string &name = id.empty() ? unknown_subscriber : id;
159 
160  if (counter == 0)
161  {
162  AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name));
163  // This is for the case that we do not abort after the exception
164  return;
165  }
166 
167  std::lock_guard<std::mutex> lock(mutex);
168 
169  map_iterator it = counter_map.find(name);
170  if (it == counter_map.end())
171  {
172  AssertNothrow(it != counter_map.end(),
173  ExcNoSubscriber(object_info->name(), name));
174  // This is for the case that we do not abort after the exception
175  return;
176  }
177  if (it->second == 0)
178  {
179  AssertNothrow(it->second > 0, ExcNoSubscriber(object_info->name(), name));
180  // This is for the case that we do not abort after the exception
181  return;
182  }
183 
184  auto validity_ptr_it =
185  std::find(validity_pointers.begin(), validity_pointers.end(), validity);
186  if (validity_ptr_it == validity_pointers.end())
187  {
189  validity_ptr_it != validity_pointers.end(),
190  ExcMessage(
191  "This Subscriptor object does not know anything about the supplied pointer!"));
192  return;
193  }
194 
195  validity_pointers.erase(validity_ptr_it);
196  --counter;
197  --it->second;
198 }
199 
200 
201 
202 void
204 {
205  list_subscribers(deallog);
206 }
207 
208 DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcInUse(int arg1, std::string arg2, std::string arg3)
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1471
std::vector< std::atomic< bool > * > validity_pointers
Definition: subscriptor.h:233
const std::type_info * object_info
Definition: subscriptor.h:241
Subscriptor & operator=(const Subscriptor &)
Definition: subscriptor.h:283
void unsubscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:155
void list_subscribers() const
Definition: subscriptor.cc:203
static ::ExceptionBase & ExcMessage(std::string arg1)
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:135
std::map< std::string, unsigned int > counter_map
Definition: subscriptor.h:217
decltype(counter_map)::iterator map_iterator
Definition: subscriptor.h:227
std::atomic< unsigned int > counter
Definition: subscriptor.h:211
static std::mutex mutex
Definition: subscriptor.h:263
virtual ~Subscriptor()
Definition: subscriptor.cc:44
static ::ExceptionBase & ExcNoSubscriber(std::string arg1, std::string arg2)
void check_no_subscribers() const noexcept
Definition: subscriptor.cc:53