Skip to content

fix(Foundation): Fix deadlock in NotificationCenter removeObserver#5114

Merged
matejk merged 1 commit intomainfrom
4970-notification-deadlock
Dec 18, 2025
Merged

fix(Foundation): Fix deadlock in NotificationCenter removeObserver#5114
matejk merged 1 commit intomainfrom
4970-notification-deadlock

Conversation

@matejk
Copy link
Copy Markdown
Contributor

@matejk matejk commented Dec 17, 2025

Summary

Fix deadlock when calling removeEventHandler() from another thread while also calling it from within an event handler (reactor thread).

Problem

A deadlock occurred due to lock ordering inversion:

  • Thread 1 (external): NotificationCenter::_mutexNObserver::_mutex
  • Thread 2 (handler): NObserver::_mutexNotificationCenter::_mutex

When Thread 1 called removeObserver() holding _mutex and trying to call disable(), while Thread 2 was in notify() holding NObserver::_mutex and the handler called removeObserver(), both threads would deadlock.

Solution

  1. Make _pObject atomic in NObserver and Observer to allow safe concurrent access without always requiring the mutex
  2. Call disable() outside the lock in NotificationCenter::removeObserver() and destructor

The fix breaks the nested lock acquisition by releasing NotificationCenter::_mutex before calling disable().

Changes

  • NObserver.h: Changed C* _pObject to std::atomic<C*> _pObject
  • Observer.h: Same change (deprecated but still used)
  • NotificationCenter.cpp: Modified removeObserver() and destructor to call disable() after releasing the lock

Fixes #4970

@matejk matejk merged commit 1c4fa8c into main Dec 18, 2025
86 checks passed
@matejk matejk deleted the 4970-notification-deadlock branch December 18, 2025 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Net: Deadlock in SocketReactor when removing handler from callback

1 participant