From ed0bb17d1d2162b40f1653c8c46903a2830fd5e4 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Fri, 27 Mar 2026 13:44:13 -0400 Subject: [PATCH] MMCore: simplify notificationQueueMutex_ - Switch from std::shared_mutex to plain std::mutex, because this uncontended and briefly held mutex is unlikely to benefit from a read-write lock (if anything, shared_mutex may have more overhead) - In postNotification(), only hold notificationQueueMutex_ while making a copy of the shared_ptr to the queue, and perform the push outside it. This is safe because: - If the queue doesn't exist, no behavior change (no push) - If the queue exists and a callback swap is happening concurrently, the queue is not swapped so no notifications are lost - If the queue exists and a callback unregister is happening concurrently, we have a slight increase in concurrency but no behavioral change because the queue is dropped after joining the delivery thread; the concurrently posted notifications are dropped in either case and this is not a problem (Assisted by Claude Code; any errors are mine.) --- MMCore/MMCore.cpp | 14 +++++++++----- MMCore/MMCore.h | 3 +-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index c6c9f438f..476debf2e 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -7769,7 +7769,7 @@ void CMMCore::registerCallback(MMEventCallback* cb) MMCORE_LEGACY_THROW(CMMError if (cb) { if (!notificationQueue_) { auto queue = std::make_shared(); - std::unique_lock lock(notificationQueueMutex_); + std::lock_guard lock(notificationQueueMutex_); notificationQueue_ = queue; } @@ -7786,7 +7786,7 @@ void CMMCore::registerCallback(MMEventCallback* cb) MMCORE_LEGACY_THROW(CMMError } }); } else { - std::unique_lock lock(notificationQueueMutex_); + std::lock_guard lock(notificationQueueMutex_); notificationQueue_.reset(); } } @@ -7794,9 +7794,13 @@ void CMMCore::registerCallback(MMEventCallback* cb) MMCORE_LEGACY_THROW(CMMError void CMMCore::postNotification(mmi::Notification notification) { - std::shared_lock lock(notificationQueueMutex_); - if (notificationQueue_) - notificationQueue_->Push(std::move(notification)); + std::shared_ptr q; + { + std::lock_guard lock(notificationQueueMutex_); + q = notificationQueue_; + } + if (q) + q->Push(std::move(notification)); } diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index d032441a8..a8a57947d 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -738,7 +737,7 @@ class CMMCore bool isLoadingSystemConfiguration_ = false; std::mutex callbackMutex_; // Serializes registerCallback() calls - std::shared_mutex notificationQueueMutex_; // Protects notificationQueue_ + std::mutex notificationQueueMutex_; // Protects notificationQueue_ std::shared_ptr notificationQueue_; std::thread notificationDeliveryThread_;