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