diff --git a/src/core/runtime/MessageQueue.cpp b/src/core/runtime/MessageQueue.cpp index d7bf29030..d6fce1a1f 100755 --- a/src/core/runtime/MessageQueue.cpp +++ b/src/core/runtime/MessageQueue.cpp @@ -132,7 +132,8 @@ void MessageQueue::RegisterForBroadcasts(IMessageTargetPtr target) { void MessageQueue::UnregisterForBroadcasts(IMessageTarget *target) { LockT lock(this->queueMutex); for (auto it : this->receivers) { - if (it.get() == target) { + auto shared = it.lock(); + if (shared && shared.get() == target) { this->receivers.erase(it); return; } @@ -242,19 +243,40 @@ void MessageQueue::Dispatch(IMessagePtr message) { message->Target()->ProcessMessage(*message); } else { - std::set copy; + std::set copy; + /* copy to dispatch outside of a lock */ { LockT lock(this->queueMutex); - std::copy( receivers.begin(), receivers.end(), std::inserter(copy, copy.begin())); } + /* dispatch */ + bool prune = false; for (auto receiver : copy) { - receiver->ProcessMessage(*message); + auto shared = receiver.lock(); + if (shared) { + shared->ProcessMessage(*message); + } + else { + prune = true; + } + } + + if (prune) { /* at least one of our weak_ptrs is dead. */ + LockT lock(this->queueMutex); + auto it = this->receivers.begin(); + while (it != this->receivers.end()) { + if (it->expired()) { + it = this->receivers.erase(it); + } + else { + ++it; + } + } } } } diff --git a/src/core/runtime/MessageQueue.h b/src/core/runtime/MessageQueue.h index 9567f8a70..ad621a6e5 100755 --- a/src/core/runtime/MessageQueue.h +++ b/src/core/runtime/MessageQueue.h @@ -65,15 +65,25 @@ namespace musik { namespace core { namespace runtime { } private: + typedef std::weak_ptr IWeakMessageTarget; + + struct EnqueuedMessage { IMessagePtr message; std::chrono::milliseconds time; }; + struct WeakPtrLess { /* https://stackoverflow.com/a/12875729 */ + template + bool operator() (const std::weak_ptr& l, const std::weak_ptr& r) const { + return l.lock().get() < r.lock().get(); + } + }; + std::mutex queueMutex; std::list queue; std::list dispatch; - std::set receivers; + std::set receivers; std::condition_variable_any waitForDispatch; std::atomic nextMessageTime; diff --git a/src/musikcube/app/layout/SettingsLayout.cpp b/src/musikcube/app/layout/SettingsLayout.cpp index a8ba3623d..caad3014e 100755 --- a/src/musikcube/app/layout/SettingsLayout.cpp +++ b/src/musikcube/app/layout/SettingsLayout.cpp @@ -544,6 +544,7 @@ void SettingsLayout::OnAddedToParent(IWindow* parent) { auto receiver = this; #endif MessageQueue().RegisterForBroadcasts(receiver->shared_from_this()); + MessageQueue().RegisterForBroadcasts(receiver->shared_from_this()); } void SettingsLayout::OnRemovedFromParent(IWindow* parent) {