Reference documentation for deal.II version 8.5.1
subscriptor.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2016 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 #ifdef DEBUG
28 namespace
29 {
30 // create a lock that might be used to control subscription to and
31 // unsubscription from objects, as that might happen in parallel.
32 // since it should happen rather seldom that several threads try to
33 // operate on different objects at the same time (the usual case is
34 // that they subscribe to the same object right after thread
35 // creation), a global lock should be sufficient, rather than one that
36 // operates on a per-object base (in which case we would have to
37 // include the huge <thread_management.h> file into the
38 // <subscriptor.h> file).
39  Threads::Mutex subscription_lock;
40 }
41 #endif
42 
43 
44 static const char *unknown_subscriber = "unknown subscriber";
45 
46 
48  :
49  counter (0),
50  object_info (0)
51 {
52  // this has to go somewhere to avoid an extra warning.
53  (void)unknown_subscriber;
54 }
55 
56 
57 
59  :
60  counter (0),
61  object_info (0)
62 {}
63 
64 
65 
66 #ifdef DEAL_II_WITH_CXX11
68  :
69  counter(0),
70  object_info (subscriptor.object_info)
71 {
72  subscriptor.check_no_subscribers();
73 }
74 #endif
75 
76 
77 
79 {
81 
82 #ifdef DEAL_II_WITH_CXX11
83  object_info = nullptr;
84 #else
85  object_info = 0;
86 #endif
87 }
88 
89 
91 {
92  // Check whether there are still subscriptions to this object. If so, output
93  // the actual name of the class to which this object belongs, i.e. the most
94  // derived class. Note that the name may be mangled, so it need not be the
95  // clear-text class name. However, you can obtain the latter by running the
96  // c++filt program over the output.
97 #ifdef DEBUG
98 
99  // If there are still active pointers, show a message and kill the program.
100  // However, under some circumstances, this is not so desirable. For example,
101  // in code like this:
102  //
103  // Triangulation tria;
104  // DoFHandler *dh = new DoFHandler(tria);
105  // ...some function that throws an exception
106  //
107  // the exception will lead to the destruction of the triangulation, but since
108  // the dof_handler is on the heap it will not be destroyed. This will trigger
109  // an assertion in the triangulation. If we kill the program at this point, we
110  // will never be able to learn what caused the problem. In this situation,
111  // just display a message and continue the program.
112  if (counter != 0)
113  {
114  if (std::uncaught_exception() == false)
115  {
116  std::string infostring;
117  for (map_iterator it = counter_map.begin(); it != counter_map.end(); ++it)
118  {
119  if (it->second > 0)
120  infostring += std::string("\n from Subscriber ")
121  + std::string(it->first);
122  }
123 
124  if (infostring == "")
125  infostring = "<none>";
126 
127  AssertNothrow (counter == 0,
128  ExcInUse (counter, object_info->name(), infostring));
129  }
130  else
131  {
132  std::cerr << "---------------------------------------------------------"
133  << std::endl
134  << "An object pointed to by a SmartPointer is being destroyed."
135  << std::endl
136  << "Under normal circumstances, this would abort the program."
137  << std::endl
138  << "However, another exception is being processed at the"
139  << std::endl
140  << "moment, so the program will continue to run to allow"
141  << std::endl
142  << "this exception to be processed."
143  << std::endl
144  << "---------------------------------------------------------"
145  << std::endl;
146  }
147  }
148 
149 #endif
150 }
151 
152 
153 
155 {
157  return *this;
158 }
159 
160 
161 
162 #ifdef DEAL_II_WITH_CXX11
164 {
166  object_info = s.object_info;
167  return *this;
168 }
169 #endif
170 
171 
172 void
173 Subscriptor::subscribe(const char *id) const
174 {
175 #ifdef DEBUG
176  if (object_info == 0)
177  object_info = &typeid(*this);
178  Threads::Mutex::ScopedLock lock (subscription_lock);
179  ++counter;
180 
181 # ifndef DEAL_II_WITH_THREADS
182  const char *const name = (id != 0) ? id : unknown_subscriber;
183 
184  map_iterator it = counter_map.find(name);
185  if (it == counter_map.end())
186  counter_map.insert(map_value_type(name, 1U));
187 
188  else
189  it->second++;
190 # else
191  (void)id;
192 # endif
193 #else
194  (void)id;
195 #endif
196 }
197 
198 
199 void
200 Subscriptor::unsubscribe(const char *id) const
201 {
202 #ifdef DEBUG
203  const char *name = (id != 0) ? id : unknown_subscriber;
204  AssertNothrow (counter>0, ExcNoSubscriber(object_info->name(), name));
205  // This is for the case that we do
206  // not abort after the exception
207  if (counter == 0)
208  return;
209 
210  Threads::Mutex::ScopedLock lock (subscription_lock);
211  --counter;
212 
213 # ifndef DEAL_II_WITH_THREADS
214  map_iterator it = counter_map.find(name);
215  AssertNothrow (it != counter_map.end(), ExcNoSubscriber(object_info->name(), name));
216  AssertNothrow (it->second > 0, ExcNoSubscriber(object_info->name(), name));
217 
218  it->second--;
219 # endif
220 #else
221  (void)id;
222 #endif
223 }
224 
225 
226 
227 unsigned int Subscriptor::n_subscriptions () const
228 {
229  return counter;
230 }
231 
232 
233 
235 {
236 #ifndef DEAL_II_WITH_THREADS
237  for (map_iterator it = counter_map.begin();
238  it != counter_map.end(); ++it)
239  deallog << it->second << '/'
240  << counter << " subscriptions from \""
241  << it->first << '\"' << std::endl;
242 #else
243  deallog << "No subscriber listing with multithreading" << std::endl;
244 #endif
245 }
246 
247 DEAL_II_NAMESPACE_CLOSE
#define AssertNothrow(cond, exc)
Definition: exceptions.h:342
const std::type_info * object_info
Definition: subscriptor.h:217
void check_no_subscribers() const
Definition: subscriptor.cc:90
Subscriptor & operator=(const Subscriptor &)
Definition: subscriptor.cc:154
static ::ExceptionBase & ExcInUse(int arg1, char *arg2, std::string &arg3)
DEAL_VOLATILE unsigned int counter
Definition: subscriptor.h:203
void subscribe(const char *identifier=0) const
Definition: subscriptor.cc:173
void list_subscribers() const
Definition: subscriptor.cc:234
unsigned int n_subscriptions() const
Definition: subscriptor.cc:227
void unsubscribe(const char *identifier=0) const
Definition: subscriptor.cc:200
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:78
std::map< const char *, unsigned int >::value_type map_value_type
Definition: subscriptor.h:179
static ::ExceptionBase & ExcNoSubscriber(char *arg1, char *arg2)