Reference documentation for deal.II version Git 6d63218887 2020-10-30 17:17:53 -0400
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
subscriptor.cc
Go to the documentation of this file.
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>
18 
19 #include <algorithm>
20 #include <iostream>
21 #include <string>
22 #include <typeinfo>
23 
25 
26 
27 static const char *unknown_subscriber = "unknown subscriber";
28 
29 
30 std::mutex Subscriptor::mutex;
31 
32 
33 Subscriptor::Subscriptor(Subscriptor &&subscriptor) noexcept
34  : counter(0)
35  , object_info(subscriptor.object_info)
36 {
37  for (const auto validity_ptr : subscriptor.validity_pointers)
38  *validity_ptr = false;
39  subscriptor.validity_pointers.clear();
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  s.validity_pointers.clear();
129  object_info = s.object_info;
130  return *this;
131 }
132 
133 
134 
135 void
136 Subscriptor::subscribe(std::atomic<bool> *const validity,
137  const std::string & id) const
138 {
139  std::lock_guard<std::mutex> lock(mutex);
140 
141  if (object_info == nullptr)
142  object_info = &typeid(*this);
143  ++counter;
144 
145  const std::string &name = id.empty() ? unknown_subscriber : id;
146 
147  ++counter_map[name];
148 
149  *validity = true;
150  validity_pointers.push_back(validity);
151 }
152 
153 
154 
155 void
156 Subscriptor::unsubscribe(std::atomic<bool> *const validity,
157  const std::string & id) const
158 {
159  const std::string &name = id.empty() ? unknown_subscriber : id;
160 
161  if (counter == 0)
162  {
163  AssertNothrow(counter > 0, ExcNoSubscriber(object_info->name(), name));
164  // This is for the case that we do not abort after the exception
165  return;
166  }
167 
168  std::lock_guard<std::mutex> lock(mutex);
169 
170  map_iterator it = counter_map.find(name);
171  if (it == counter_map.end())
172  {
173  AssertNothrow(it != counter_map.end(),
174  ExcNoSubscriber(object_info->name(), name));
175  // This is for the case that we do not abort after the exception
176  return;
177  }
178  if (it->second == 0)
179  {
180  AssertNothrow(it->second > 0, ExcNoSubscriber(object_info->name(), name));
181  // This is for the case that we do not abort after the exception
182  return;
183  }
184 
185  auto validity_ptr_it =
186  std::find(validity_pointers.begin(), validity_pointers.end(), validity);
187  if (validity_ptr_it == validity_pointers.end())
188  {
190  validity_ptr_it != validity_pointers.end(),
191  ExcMessage(
192  "This Subscriptor object does not know anything about the supplied pointer!"));
193  return;
194  }
195 
196  validity_pointers.erase(validity_ptr_it);
197  --counter;
198  --it->second;
199 }
200 
201 
202 
203 void
205 {
207 }
208 
static ::ExceptionBase & ExcInUse(int arg1, std::string arg2, std::string arg3)
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1486
std::vector< std::atomic< bool > * > validity_pointers
Definition: subscriptor.h:241
const std::type_info * object_info
Definition: subscriptor.h:249
LogStream deallog
Definition: logstream.cc:37
Subscriptor & operator=(const Subscriptor &)
Definition: subscriptor.h:291
void unsubscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:156
void list_subscribers() const
Definition: subscriptor.cc:204
static ::ExceptionBase & ExcMessage(std::string arg1)
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
Definition: subscriptor.cc:136
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:369
std::map< std::string, unsigned int > counter_map
Definition: subscriptor.h:225
decltype(counter_map)::iterator map_iterator
Definition: subscriptor.h:235
std::atomic< unsigned int > counter
Definition: subscriptor.h:219
static const char * unknown_subscriber
Definition: subscriptor.cc:27
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:368
static std::mutex mutex
Definition: subscriptor.h:271
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