Reference documentation for deal.II version GIT relicensing-136-gb80d0be4af 2024-03-18 08:20:02+00:00
\(\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\}}\)
Loading...
Searching...
No Matches
subscriptor.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 1998 - 2023 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
17
18#include <algorithm>
19#include <iostream>
20#include <string>
21#include <typeinfo>
22
24
25
26static const char *unknown_subscriber = "unknown subscriber";
27
28
29std::mutex Subscriptor::mutex;
30
31
33 : counter(0)
34 , object_info(subscriptor.object_info)
35{
36 for (auto *const validity_ptr : subscriptor.validity_pointers)
37 *validity_ptr = false;
38 subscriptor.validity_pointers.clear();
39}
40
41
42
44{
45 for (auto *const validity_ptr : validity_pointers)
46 *validity_ptr = false;
47 object_info = nullptr;
48}
49
50
51void
53{
54 // Check whether there are still subscriptions to this object. If so, output
55 // the actual name of the class to which this object belongs, i.e. the most
56 // derived class. Note that the name may be mangled, so it need not be the
57 // clear-text class name. However, you can obtain the latter by running the
58 // c++filt program over the output.
59#ifdef DEBUG
60
61 // If there are still active pointers, show a message and kill the program.
62 // However, under some circumstances, this is not so desirable. For example,
63 // in code like this:
64 //
65 // Triangulation tria;
66 // DoFHandler *dh = new DoFHandler(tria);
67 // ...some function that throws an exception
68 //
69 // the exception will lead to the destruction of the triangulation, but since
70 // the dof_handler is on the heap it will not be destroyed. This will trigger
71 // an assertion in the triangulation. If we kill the program at this point, we
72 // will never be able to learn what caused the problem. In this situation,
73 // just display a message and continue the program.
74 if (counter != 0)
75 {
76# if __cpp_lib_uncaught_exceptions >= 201411
77 // std::uncaught_exception() is deprecated in c++17
78 if (std::uncaught_exceptions() == 0)
79# else
80 if (std::uncaught_exception() == false)
81# endif
82 {
83 std::string infostring;
84 for (const auto &map_entry : counter_map)
85 {
86 if (map_entry.second > 0)
87 infostring += std::string("\n from Subscriber ") +
88 std::string(map_entry.first);
89 }
90
91 if (infostring.empty())
92 infostring = "<none>";
93
95 ExcInUse(counter.load(),
96 object_info->name(),
97 infostring));
98 }
99 else
100 {
101 std::cerr
102 << "---------------------------------------------------------"
103 << std::endl
104 << "An object pointed to by a SmartPointer is being destroyed."
105 << std::endl
106 << "Under normal circumstances, this would abort the program."
107 << std::endl
108 << "However, another exception is being processed at the"
109 << std::endl
110 << "moment, so the program will continue to run to allow"
111 << std::endl
112 << "this exception to be processed." << std::endl
113 << "---------------------------------------------------------"
114 << std::endl;
115 }
116 }
117#endif
118}
119
120
121
124{
125 for (auto *const validity_ptr : s.validity_pointers)
126 *validity_ptr = false;
127 s.validity_pointers.clear();
128 object_info = s.object_info;
129 return *this;
130}
131
132
133
134void
135Subscriptor::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
154void
155Subscriptor::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 {
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(),
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
202void
207
std::vector< std::atomic< bool > * > validity_pointers
void unsubscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
std::atomic< unsigned int > counter
void check_no_subscribers() const noexcept
void list_subscribers() const
const std::type_info * object_info
Subscriptor & operator=(const Subscriptor &)
void subscribe(std::atomic< bool > *const validity, const std::string &identifier="") const
std::map< std::string, unsigned int > counter_map
static std::mutex mutex
decltype(counter_map)::iterator map_iterator
virtual ~Subscriptor()
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:502
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:503
static ::ExceptionBase & ExcInUse(int arg1, std::string arg2, std::string arg3)
#define AssertNothrow(cond, exc)
static ::ExceptionBase & ExcNoSubscriber(std::string arg1, std::string arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
LogStream deallog
Definition logstream.cc:36
static const char * unknown_subscriber