Reference documentation for deal.II version 9.1.1
\(\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 (std::uncaught_exception() == false)
78  {
79  std::string infostring;
80  for (const auto &map_entry : counter_map)
81  {
82  if (map_entry.second > 0)
83  infostring += std::string("\n from Subscriber ") +
84  std::string(map_entry.first);
85  }
86 
87  if (infostring.empty())
88  infostring = "<none>";
89 
91  ExcInUse(counter.load(),
92  object_info->name(),
93  infostring));
94  }
95  else
96  {
97  std::cerr
98  << "---------------------------------------------------------"
99  << std::endl
100  << "An object pointed to by a SmartPointer is being destroyed."
101  << std::endl
102  << "Under normal circumstances, this would abort the program."
103  << std::endl
104  << "However, another exception is being processed at the"
105  << std::endl
106  << "moment, so the program will continue to run to allow"
107  << std::endl
108  << "this exception to be processed." << std::endl
109  << "---------------------------------------------------------"
110  << std::endl;
111  }
112  }
113 #endif
114 }
115 
116 
117 
118 Subscriptor &
120 {
121  for (const auto validity_ptr : s.validity_pointers)
122  *validity_ptr = false;
123  object_info = s.object_info;
124  return *this;
125 }
126 
127 
128 
129 void
130 Subscriptor::subscribe(std::atomic<bool> *const validity,
131  const std::string & id) const
132 {
133  std::lock_guard<std::mutex> lock(mutex);
134 
135  if (object_info == nullptr)
136  object_info = &typeid(*this);
137  ++counter;
138 
139  const std::string &name = id.empty() ? unknown_subscriber : id;
140 
141  ++counter_map[name];
142 
143  *validity = true;
144  validity_pointers.push_back(validity);
145 }
146 
147 
148 
149 void
150 Subscriptor::unsubscribe(std::atomic<bool> *const validity,
151  const std::string & id) const
152 {
153  const std::string &name = id.empty() ? unknown_subscriber : id;
154 
155  if (counter == 0)
156  {
157  AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name));
158  // This is for the case that we do not abort after the exception
159  return;
160  }
161 
162  std::lock_guard<std::mutex> lock(mutex);
163 
164  map_iterator it = counter_map.find(name);
165  if (it == counter_map.end())
166  {
167  AssertNothrow(it != counter_map.end(),
168  ExcNoSubscriber(object_info->name(), name));
169  // This is for the case that we do not abort after the exception
170  return;
171  }
172  if (it->second == 0)
173  {
174  AssertNothrow(it->second > 0, ExcNoSubscriber(object_info->name(), name));
175  // This is for the case that we do not abort after the exception
176  return;
177  }
178 
179  auto validity_ptr_it =
180  std::find(validity_pointers.begin(), validity_pointers.end(), validity);
181  if (validity_ptr_it == validity_pointers.end())
182  {
184  validity_ptr_it != validity_pointers.end(),
185  ExcMessage(
186  "This Subscriptor object does not know anything about the supplied pointer!"));
187  return;
188  }
189 
190  validity_pointers.erase(validity_ptr_it);
191  --counter;
192  --it->second;
193 }
194 
195 
196 
197 void
199 {
200  list_subscribers(deallog);
201 }
202 
203 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:150
void list_subscribers() const
Definition: subscriptor.cc:198
static ::ExceptionBase & ExcMessage(std::string arg1)
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:130
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