source: src/Patterns/Observer.cpp@ 317df8

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 317df8 was 317df8, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Changed Observer to use RAII-style for locking changes.

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/*
2 * Observer.cpp
3 *
4 * Created on: Jan 19, 2010
5 * Author: crueger
6 */
7
8#include "Observer.hpp"
9
10
11#include <iostream>
12#include <cassert>
13
14using namespace std;
15
16/****************** Static stuff for the observer mechanism ************/
17
18// All infrastructure for the observer-pattern is bundled at a central place
19// this is more efficient if many objects can be observed (inherit from observable)
20// but only few are actually coupled with observers. E.g. TMV has over 500.000 Atoms,
21// which might become observable. Handling Observerable infrastructure in each of
22// these would use memory for each atom. By handling Observer-infrastructure
23// here we only need memory for objects that actually are observed.
24// See [Gamma et al, 1995] p. 297
25
26map<Observable*, int> Observable::depth;
27map<Observable*,multimap<int,Observer*>*> Observable::callTable;
28set<Observable*> Observable::busyObservables;
29
30// The two functions start_observer_internal and finish_observer_internal
31// have to be used together at all time. Never use these functions directly
32// START_OBSERVER and FINISH_OBSERVER also construct a bogus while(0) loop
33// thus producing compiler-errors whenever only one is used
34
35void Observable::start_observer_internal(Observable *publisher){
36 // increase the count for this observable by one
37 // if no entry for this observable is found, an new one is created
38 // by the STL and initialized to 0 (see STL documentation)
39 depth[publisher]++;
40}
41
42void Observable::finish_observer_internal(Observable *publisher){
43 // decrease the count for this observable
44 // if zero is reached all observed blocks are done and we can
45 // start to notify our observers
46 if(--(depth[publisher])){}
47 else{
48 publisher->notifyAll();
49 // this item is done, so we don't have to keep the count with us
50 // save some memory by erasing it
51 depth.erase(publisher);
52 }
53}
54
55Observable::_Observable_protector::_Observable_protector(Observable *_protege) :
56 protege(_protege)
57{
58 start_observer_internal(protege);
59}
60
61Observable::_Observable_protector::~_Observable_protector()
62{
63 finish_observer_internal(protege);
64}
65
66/************* Notification mechanism for observables **************/
67
68
69void Observable::notifyAll() {
70 // we are busy notifying others right now
71 // add ourselves to the list of busy subjects to enable circle detection
72 busyObservables.insert(this);
73 // see if anyone has signed up for observation
74 // and call all observers
75 if(callTable.count(this)) {
76 // elements are stored sorted by keys in the multimap
77 // so iterating over it gives us a the callees sorted by
78 // the priorities
79 callees_t *callees = callTable[this];
80 callees_t::iterator iter;
81 for(iter=callees->begin();iter!=callees->end();iter++){
82 (*iter).second->update(this);
83 }
84 }
85 // done with notification, we can leave the set of busy subjects
86 busyObservables.erase(this);
87}
88
89// this handles passing on updates from sub-Observables
90void Observable::update(Observable *publisher) {
91 // circle detection
92 if(busyObservables.find(this)!=busyObservables.end()) {
93 // somehow a circle was introduced... we were busy notifying our
94 // observers, but still we are called by one of our sub-Observables
95 // we cannot be sure observation will still work at this point
96 cerr << "Circle detected in observation-graph." << endl;
97 cerr << "Observation-graph always needs to be a DAG to work correctly!" << endl;
98 cerr << "Please check your observation code and fix this!" << endl;
99 return;
100 }
101 else {
102 // see if we are in the process of changing ourselves
103 // if we are changing ourselves at the same time our sub-observables change
104 // we do not need to publish all the changes at each time we are called
105 if(depth.find(this)==depth.end()) {
106 notifyAll();
107 }
108 }
109}
110
111// methods to sign-on and off
112void Observable::signOn(Observer *target,int priority) {
113 assert(priority>=-20 && priority<=+20 && "Priority out of range [-20:+20]");
114 bool res = false;
115 callees_t *callees = 0;
116 if(callTable.count(this)){
117 callees = callTable[this];
118 }
119 else {
120 callees = new multimap<int,Observer*>;
121 callTable.insert(pair<Observable*,callees_t*>(this,callees));
122 }
123
124 callees_t::iterator iter;
125 for(iter=callees->begin();iter!=callees->end();iter++){
126 res |= ((*iter).second == target);
127 }
128 if(!res)
129 callees->insert(pair<int,Observer*>(priority,target));
130}
131
132void Observable::signOff(Observer *target) {
133 assert(callTable.count(this) && "SignOff called for an Observable without Observers.");
134 callees_t *callees = callTable[this];
135 callees_t::iterator iter;
136 for(iter=callees->begin();iter!=callees->end();iter++) {
137 if((*iter).second == target)
138 callees->erase(iter);
139 }
140 if(callees->empty()){
141 callTable.erase(this);
142 delete callees;
143 }
144}
145
146// when an sub-observerable dies we usually don't need to do anything
147void Observable::subjectKilled(Observable *publisher){
148}
149
150Observable::Observable()
151{}
152
153// when an observable is deleted, we let all our observers know
154Observable::~Observable()
155{
156 if(callTable.count(this)) {
157 // delete all entries for this observable
158 callees_t *callees = callTable[this];
159 callees_t::iterator iter;
160 for(iter=callees->begin();iter!=callees->end();iter++){
161 (*iter).second->subjectKilled(this);
162 }
163 callTable.erase(this);
164 delete callees;
165 }
166}
167
168Observer::Observer()
169{}
170
171Observer::~Observer()
172{}
Note: See TracBrowser for help on using the repository browser.