Skip to content

Commit 7bbf058

Browse files
committed
Implement notification loop safeguard in ofParameter<void>
1 parent 29f5ede commit 7bbf058

File tree

2 files changed

+58
-35
lines changed

2 files changed

+58
-35
lines changed

libs/openFrameworks/types/ofParameter.cpp

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -105,50 +105,70 @@ ofParameter<void>& ofParameter<void>::set(const std::string & name){
105105
}
106106

107107
void ofParameter<void>::trigger(){
108-
ofNotifyEvent(obj->changedE,this);
109-
// Notify all parents, if there are any.
110-
if(!obj->parents.empty())
108+
// If the object is notifying its parents, just set the value without triggering an event.
109+
if(!obj->bInNotify)
111110
{
112-
// Erase each invalid parent
113-
obj->parents.erase(std::remove_if(obj->parents.begin(),
114-
obj->parents.end(),
115-
[this](const std::weak_ptr<ofParameterGroup::Value> & p){ return p.expired(); }),
116-
obj->parents.end());
117-
118-
// notify all leftover (valid) parents of this object's changed value.
119-
// this can't happen in the same iterator as above, because a notified listener
120-
// might perform similar cleanups that would corrupt our iterator
121-
// (which appens for example if the listener calls getFirstParent on us)
122-
for(auto & parent: obj->parents){
123-
auto p = parent.lock();
124-
if(p){
125-
p->notifyParameterChanged(*this);
111+
// Mark the object as in its notification loop.
112+
obj->bInNotify = true;
113+
114+
// Notify any local subscribers.
115+
ofNotifyEvent(obj->changedE, this);
116+
117+
// Notify all parents, if there are any.
118+
if(!obj->parents.empty())
119+
{
120+
// Erase each invalid parent
121+
obj->parents.erase(std::remove_if(obj->parents.begin(),
122+
obj->parents.end(),
123+
[this](const std::weak_ptr<ofParameterGroup::Value> & p){ return p.expired(); }),
124+
obj->parents.end());
125+
126+
// notify all leftover (valid) parents of this object's changed value.
127+
// this can't happen in the same iterator as above, because a notified listener
128+
// might perform similar cleanups that would corrupt our iterator
129+
// (which appens for example if the listener calls getFirstParent on us)
130+
for(auto & parent: obj->parents){
131+
auto p = parent.lock();
132+
if(p){
133+
p->notifyParameterChanged(*this);
134+
}
126135
}
127136
}
137+
obj->bInNotify = false;
128138
}
129139
}
130140

131141
void ofParameter<void>::trigger(const void * sender){
132-
ofNotifyEvent(obj->changedE,sender);
133-
// Notify all parents, if there are any.
134-
if(!obj->parents.empty())
142+
// If the object is notifying its parents, Do not trigger the event.
143+
if(!obj->bInNotify)
135144
{
136-
// Erase each invalid parent
137-
obj->parents.erase(std::remove_if(obj->parents.begin(),
138-
obj->parents.end(),
139-
[this](const std::weak_ptr<ofParameterGroup::Value> & p){ return p.expired(); }),
140-
obj->parents.end());
141-
142-
// notify all leftover (valid) parents of this object's changed value.
143-
// this can't happen in the same iterator as above, because a notified listener
144-
// might perform similar cleanups that would corrupt our iterator
145-
// (which appens for example if the listener calls getFirstParent on us)
146-
for(auto & parent: obj->parents){
147-
auto p = parent.lock();
148-
if(p){
149-
p->notifyParameterChanged(*this);
145+
// Mark the object as in its notification loop.
146+
obj->bInNotify = true;
147+
148+
// Notify any local subscribers.
149+
ofNotifyEvent(obj->changedE, this);
150+
151+
// Notify all parents, if there are any.
152+
if(!obj->parents.empty())
153+
{
154+
// Erase each invalid parent
155+
obj->parents.erase(std::remove_if(obj->parents.begin(),
156+
obj->parents.end(),
157+
[this](const std::weak_ptr<ofParameterGroup::Value> & p){ return p.expired(); }),
158+
obj->parents.end());
159+
160+
// notify all leftover (valid) parents of this object's changed value.
161+
// this can't happen in the same iterator as above, because a notified listener
162+
// might perform similar cleanups that would corrupt our iterator
163+
// (which appens for example if the listener calls getFirstParent on us)
164+
for(auto & parent: obj->parents){
165+
auto p = parent.lock();
166+
if(p){
167+
p->notifyParameterChanged(*this);
168+
}
150169
}
151170
}
171+
obj->bInNotify = false;
152172
}
153173
}
154174

libs/openFrameworks/types/ofParameter.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,14 +1054,17 @@ class ofParameter<void>: public ofAbstractParameter{
10541054
class Value{
10551055
public:
10561056
Value()
1057-
:serializable(false){}
1057+
:bInNotify(false)
1058+
,serializable(false){}
10581059

10591060
Value(std::string name)
10601061
:name(name)
1062+
,bInNotify(false)
10611063
,serializable(false){}
10621064

10631065
std::string name;
10641066
ofEvent<void> changedE;
1067+
bool bInNotify;
10651068
bool serializable;
10661069
std::vector<std::weak_ptr<ofParameterGroup::Value>> parents;
10671070
};

0 commit comments

Comments
 (0)