Reference documentation for deal.II version 8.4.1
subscriptor.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1998 - 2015 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 
66 {
67  // check whether there are still
68  // subscriptions to this object. if
69  // so, output the actual name of
70  // the class to which this object
71  // belongs, i.e. the most derived
72  // class. note that the name may be
73  // mangled, so it need not be the
74  // clear-text class name. however,
75  // you can obtain the latter by
76  // running the c++filt program over
77  // the output.
78 #ifdef DEBUG
79 
80  // if there are still active pointers, show
81  // a message and kill the program. However,
82  // under some circumstances, this is not so
83  // desirable. For example, in code like this
84  //
85  // Triangulation tria;
86  // DoFHandler *dh = new DoFHandler(tria);
87  // ...some function that throws an exception
88  //
89  // the exception will lead to the
90  // destruction of the triangulation, but
91  // since the dof_handler is on the heap it
92  // will not be destroyed. This will trigger
93  // an assertion in the triangulation. If we
94  // kill the program at this point, we will
95  // never be able to learn what caused the
96  // problem. In this situation, just display
97  // a message and continue the program.
98  if (counter != 0)
99  {
100  if (std::uncaught_exception() == false)
101  {
102  std::string infostring;
103  for (map_iterator it = counter_map.begin(); it != counter_map.end(); ++it)
104  {
105  if (it->second > 0)
106  infostring += std::string("\n from Subscriber ")
107  + std::string(it->first);
108  }
109 
110  if (infostring == "")
111  infostring = "<none>";
112 
113  AssertNothrow (counter == 0,
114  ExcInUse (counter, object_info->name(), infostring));
115  }
116  else
117  {
118  std::cerr << "---------------------------------------------------------"
119  << std::endl
120  << "An object pointed to by a SmartPointer is being destroyed."
121  << std::endl
122  << "Under normal circumstances, this would abort the program."
123  << std::endl
124  << "However, another exception is being processed at the"
125  << std::endl
126  << "moment, so the program will continue to run to allow"
127  << std::endl
128  << "this exception to be processed."
129  << std::endl
130  << "---------------------------------------------------------"
131  << std::endl;
132  }
133  }
134  // In case we do not abort
135  // on error, this will tell
136  // do_unsubscribe below that the
137  // object is unused now.
138  counter = 0;
139 #endif
140 }
141 
142 
143 
145 {
147  return *this;
148 }
149 
150 
151 
152 void
153 Subscriptor::subscribe(const char *id) const
154 {
155 #ifdef DEBUG
156  if (object_info == 0)
157  object_info = &typeid(*this);
158  Threads::Mutex::ScopedLock lock (subscription_lock);
159  ++counter;
160 
161 # ifndef DEAL_II_WITH_THREADS
162  const char *const name = (id != 0) ? id : unknown_subscriber;
163 
164  map_iterator it = counter_map.find(name);
165  if (it == counter_map.end())
166  counter_map.insert(map_value_type(name, 1U));
167 
168  else
169  it->second++;
170 # else
171  (void)id;
172 # endif
173 #else
174  (void)id;
175 #endif
176 }
177 
178 
179 void
180 Subscriptor::unsubscribe(const char *id) const
181 {
182 #ifdef DEBUG
183  const char *name = (id != 0) ? id : unknown_subscriber;
184  AssertNothrow (counter>0, ExcNoSubscriber(object_info->name(), name));
185  // This is for the case that we do
186  // not abort after the exception
187  if (counter == 0)
188  return;
189 
190  Threads::Mutex::ScopedLock lock (subscription_lock);
191  --counter;
192 
193 # ifndef DEAL_II_WITH_THREADS
194  map_iterator it = counter_map.find(name);
195  AssertNothrow (it != counter_map.end(), ExcNoSubscriber(object_info->name(), name));
196  AssertNothrow (it->second > 0, ExcNoSubscriber(object_info->name(), name));
197 
198  it->second--;
199 # endif
200 #else
201  (void)id;
202 #endif
203 }
204 
205 
206 
207 unsigned int Subscriptor::n_subscriptions () const
208 {
209  return counter;
210 }
211 
212 
213 
215 {
216 #ifndef DEAL_II_WITH_THREADS
217  for (map_iterator it = counter_map.begin();
218  it != counter_map.end(); ++it)
219  deallog << it->second << '/'
220  << counter << " subscriptions from \""
221  << it->first << '\"' << std::endl;
222 #else
223  deallog << "No subscriber listing with multithreading" << std::endl;
224 #endif
225 }
226 
227 DEAL_II_NAMESPACE_CLOSE
void unsubscribe(const char *identifier=0) const
Definition: subscriptor.cc:180
void subscribe(const char *identifier=0) const
Definition: subscriptor.cc:153
#define AssertNothrow(cond, exc)
Definition: exceptions.h:323
const std::type_info * object_info
Definition: subscriptor.h:198
Subscriptor & operator=(const Subscriptor &)
Definition: subscriptor.cc:144
DEAL_VOLATILE unsigned int counter
Definition: subscriptor.h:184
unsigned int n_subscriptions() const
Definition: subscriptor.cc:207
std::map< const char *, unsigned int > counter_map
Definition: subscriptor.h:190
std::map< const char *, unsigned int >::iterator map_iterator
Definition: subscriptor.h:166
virtual ~Subscriptor()
Definition: subscriptor.cc:65
std::map< const char *, unsigned int >::value_type map_value_type
Definition: subscriptor.h:160
void list_subscribers() const
Definition: subscriptor.cc:214