source: src/Patterns/Observer.cpp@ 0c1d97

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 0c1d97 was 0c1d97, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added mechanism that allows for assign priorities to observers

  • Property mode set to 100644
File size: 5.1 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
55/************* Notification mechanism for observables **************/
56
57
58void Observable::notifyAll() {
59 // we are busy notifying others right now
60 // add ourselves to the list of busy subjects to enable circle detection
61 busyObservables.insert(this);
62 // see if anyone has signed up for observation
63 // and call all observers
64 if(callTable.count(this)) {
65 // elements are stored sorted by keys in the multimap
66 // so iterating over it gives us a the callees sorted by
67 // the priorities
68 callees_t *callees = callTable[this];
69 callees_t::iterator iter;
70 for(iter=callees->begin();iter!=callees->end();iter++){
71 (*iter).second->update(this);
72 }
73 }
74 // done with notification, we can leave the set of busy subjects
75 busyObservables.erase(this);
76}
77
78// this handles passing on updates from sub-Observables
79void Observable::update(Observable *publisher) {
80 // circle detection
81 if(busyObservables.find(this)!=busyObservables.end()) {
82 // somehow a circle was introduced... we were busy notifying our
83 // observers, but still we are called by one of our sub-Observables
84 // we cannot be sure observation will still work at this point
85 cerr << "Circle detected in observation-graph." << endl;
86 cerr << "Observation-graph always needs to be a DAG to work correctly!" << endl;
87 cerr << "Please check your observation code and fix this!" << endl;
88 return;
89 }
90 else {
91 // see if we are in the process of changing ourselves
92 // if we are changing ourselves at the same time our sub-observables change
93 // we do not need to publish all the changes at each time we are called
94 if(depth.find(this)==depth.end()) {
95 notifyAll();
96 }
97 }
98}
99
100// methods to sign-on and off
101void Observable::signOn(Observer *target,int priority) {
102 assert(priority>=-20 && priority<=+20 && "Priority out of range [-20:+20]");
103 bool res = false;
104 callees_t *callees = 0;
105 if(callTable.count(this)){
106 callees = callTable[this];
107 }
108 else {
109 callees = new multimap<int,Observer*>;
110 callTable.insert(pair<Observable*,callees_t*>(this,callees));
111 }
112
113 callees_t::iterator iter;
114 for(iter=callees->begin();iter!=callees->end();iter++){
115 res |= ((*iter).second == target);
116 }
117 if(!res)
118 callees->insert(pair<int,Observer*>(priority,target));
119}
120
121void Observable::signOff(Observer *target) {
122 assert(callTable.count(this) && "SignOff called for an Observable without Observers.");
123 callees_t *callees = callTable[this];
124 callees_t::iterator iter;
125 for(iter=callees->begin();iter!=callees->end();iter++) {
126 if((*iter).second == target)
127 callees->erase(iter);
128 }
129 if(callees->empty()){
130 callTable.erase(this);
131 delete callees;
132 }
133}
134
135// when an sub-observerable dies we usually don't need to do anything
136void Observable::subjectKilled(Observable *publisher){
137}
138
139Observable::Observable()
140{}
141
142// when an observable is deleted, we let all our observers know
143Observable::~Observable()
144{
145 if(callTable.count(this)) {
146 // delete all entries for this observable
147 callees_t *callees = callTable[this];
148 callees_t::iterator iter;
149 for(iter=callees->begin();iter!=callees->end();iter++){
150 (*iter).second->subjectKilled(this);
151 }
152 callTable.erase(this);
153 delete callees;
154 }
155}
156
157Observer::Observer()
158{}
159
160Observer::~Observer()
161{}
Note: See TracBrowser for help on using the repository browser.