deal.II version GIT relicensing-1941-ga9013bea74 2024-10-08 06:50:00+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 (std::uncaught_exceptions() == 0)
77 {
78 std::string infostring;
79 for (const auto &map_entry : counter_map)
80 {
81 if (map_entry.second > 0)
82 infostring += std::string("\n from Subscriber ") +
83 std::string(map_entry.first);
84 }
85
86 if (infostring.empty())
87 infostring = "<none>";
88
90 ExcInUse(counter.load(),
91 object_info->name(),
92 infostring));
93 }
94 else
95 {
96 std::cerr
97 << "---------------------------------------------------------"
98 << std::endl
99 << "An object pointed to by a ObserverPointer is being destroyed."
100 << std::endl
101 << "Under normal circumstances, this would abort the program."
102 << std::endl
103 << "However, another exception is being processed at the"
104 << std::endl
105 << "moment, so the program will continue to run to allow"
106 << std::endl
107 << "this exception to be processed." << std::endl
108 << "---------------------------------------------------------"
109 << std::endl;
110 }
111 }
112#endif
113}
114
115
116
119{
120 for (auto *const validity_ptr : s.validity_pointers)
121 *validity_ptr = false;
122 s.validity_pointers.clear();
123 object_info = s.object_info;
124 return *this;
125}
126
127
128
129void
130Subscriptor::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
149void
150Subscriptor::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 {
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(),
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
197void
202
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:498
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:499
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