From f8b7fe0dc7573dee8775a6f4704b3f631635d826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Frigola=20Bague=CC=81?= Date: Thu, 23 Jul 2020 19:43:54 +0200 Subject: [PATCH 1/2] Implement notification loop safeguard in ofParameter --- libs/openFrameworks/types/ofParameter.cpp | 50 ++++++++++++++--------- libs/openFrameworks/types/ofParameter.h | 5 ++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/libs/openFrameworks/types/ofParameter.cpp b/libs/openFrameworks/types/ofParameter.cpp index 513e5ef330c..b5584174c4a 100644 --- a/libs/openFrameworks/types/ofParameter.cpp +++ b/libs/openFrameworks/types/ofParameter.cpp @@ -106,33 +106,42 @@ ofParameter& ofParameter::set(const std::string & name){ } void ofParameter::trigger(){ - ofNotifyEvent(obj->changedE,this); - // Notify all parents, if there are any. - if(!obj->parents.empty()) + // If the object is notifying its parents, just set the value without triggering an event. + if(!obj->bInNotify) { - // Erase each invalid parent - obj->parents.erase(std::remove_if(obj->parents.begin(), - obj->parents.end(), - [](const std::weak_ptr & p){ return p.expired(); }), - obj->parents.end()); - - // notify all leftover (valid) parents of this object's changed value. - // this can't happen in the same iterator as above, because a notified listener - // might perform similar cleanups that would corrupt our iterator - // (which appens for example if the listener calls getFirstParent on us) - for(auto & parent: obj->parents){ - auto p = parent.lock(); - if(p){ - p->notifyParameterChanged(*this); + // Mark the object as in its notification loop. + obj->bInNotify = true; + + // Notify any local subscribers. + ofNotifyEvent(obj->changedE, this); + + // Notify all parents, if there are any. + if(!obj->parents.empty()) + { + // Erase each invalid parent + obj->parents.erase(std::remove_if(obj->parents.begin(), + obj->parents.end(), + [this](const std::weak_ptr & p){ return p.expired(); }), + obj->parents.end()); + + // notify all leftover (valid) parents of this object's changed value. + // this can't happen in the same iterator as above, because a notified listener + // might perform similar cleanups that would corrupt our iterator + // (which appens for example if the listener calls getFirstParent on us) + for(auto & parent: obj->parents){ + auto p = parent.lock(); + if(p){ + p->notifyParameterChanged(*this); + } } } + obj->bInNotify = false; } } void ofParameter::trigger(const void * sender){ - ofNotifyEvent(obj->changedE,sender); - // Notify all parents, if there are any. - if(!obj->parents.empty()) + // If the object is notifying its parents, Do not trigger the event. + if(!obj->bInNotify) { // Erase each invalid parent obj->parents.erase(std::remove_if(obj->parents.begin(), @@ -150,6 +159,7 @@ void ofParameter::trigger(const void * sender){ p->notifyParameterChanged(*this); } } + obj->bInNotify = false; } } diff --git a/libs/openFrameworks/types/ofParameter.h b/libs/openFrameworks/types/ofParameter.h index 64044391a01..08a23d45a5c 100644 --- a/libs/openFrameworks/types/ofParameter.h +++ b/libs/openFrameworks/types/ofParameter.h @@ -1054,14 +1054,17 @@ class ofParameter: public ofAbstractParameter{ class Value{ public: Value() - :serializable(false){} + :bInNotify(false) + ,serializable(false){} Value(std::string name) :name(name) + ,bInNotify(false) ,serializable(false){} std::string name; ofEvent changedE; + bool bInNotify; bool serializable; std::vector> parents; }; From e057f66367f6af738527e297ecb1499c3ceb935b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduard=20Frigola=20Bague=CC=81?= Date: Thu, 23 Jul 2020 19:43:54 +0200 Subject: [PATCH 2/2] Implement notification loop safeguard in ofParameter --- libs/openFrameworks/types/ofParameter.cpp | 38 ++++++++++++++--------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/libs/openFrameworks/types/ofParameter.cpp b/libs/openFrameworks/types/ofParameter.cpp index b5584174c4a..974b42b0c31 100644 --- a/libs/openFrameworks/types/ofParameter.cpp +++ b/libs/openFrameworks/types/ofParameter.cpp @@ -143,20 +143,30 @@ void ofParameter::trigger(const void * sender){ // If the object is notifying its parents, Do not trigger the event. if(!obj->bInNotify) { - // Erase each invalid parent - obj->parents.erase(std::remove_if(obj->parents.begin(), - obj->parents.end(), - [](const std::weak_ptr & p){ return p.expired(); }), - obj->parents.end()); - - // notify all leftover (valid) parents of this object's changed value. - // this can't happen in the same iterator as above, because a notified listener - // might perform similar cleanups that would corrupt our iterator - // (which appens for example if the listener calls getFirstParent on us) - for(auto & parent: obj->parents){ - auto p = parent.lock(); - if(p){ - p->notifyParameterChanged(*this); + // Mark the object as in its notification loop. + obj->bInNotify = true; + + // Notify any local subscribers. + ofNotifyEvent(obj->changedE, this); + + // Notify all parents, if there are any. + if(!obj->parents.empty()) + { + // Erase each invalid parent + obj->parents.erase(std::remove_if(obj->parents.begin(), + obj->parents.end(), + [this](const std::weak_ptr & p){ return p.expired(); }), + obj->parents.end()); + + // notify all leftover (valid) parents of this object's changed value. + // this can't happen in the same iterator as above, because a notified listener + // might perform similar cleanups that would corrupt our iterator + // (which appens for example if the listener calls getFirstParent on us) + for(auto & parent: obj->parents){ + auto p = parent.lock(); + if(p){ + p->notifyParameterChanged(*this); + } } } obj->bInNotify = false;