Я использую Poco как часть приложения C ++ и столкнулся с проблемой, которую не совсем понимаю. Приложение было переведено с Obj-C и активно использовало NSNotificationCenter от Apple.
Чтобы сделать переход максимально безболезненным, я решил вместо этого использовать Центр уведомлений Poco. Он работает нормально, но некоторые пользователи сообщали о взаимоблокировках, которые я сейчас пытаюсь устранить.
Просто быстрый совет для тех, кто не знаком с NotificationCenter. Вы подписываетесь на уведомление, как это:
Poco::NotificationCenter& nc = Poco::NotificationCenter::defaultCenter();
nc.addObserver(Poco::NObserver<MyClass, MyNotification>(*this, &MyClass::onNotification));
и опубликуйте уведомление так:
Poco::NotificationCenter& nc = Poco::NotificationCenter::defaultCenter();
nc.postNotification(new MyNotification());
Метод postNotification () определяется следующим образом:
void NotificationCenter::postNotification(Notification::Ptr pNotification)
{
poco_check_ptr (pNotification);
ScopedLockWithUnlock<Mutex> lock(_mutex);
ObserverList observersToNotify(_observers);
lock.unlock();
for (ObserverList::iterator it = observersToNotify.begin(); it != observersToNotify.end(); ++it)
{
(*it)->notify(pNotification);
}
}
И NObserver :: notify () вот так:
void notify(Notification* pNf) const
{
Poco::Mutex::ScopedLock lock(_mutex);
if (_pObject)
{
N* pCastNf = dynamic_cast<N*>(pNf);
if (pCastNf)
{
NotificationPtr ptr(pCastNf, true);
(_pObject->*_method)(ptr);
}
}
}
Все это действительно просто и не включает никакой черной магии.
Учитывая тот факт, что метод postNotification всегда выполняет итерацию по всем наблюдателям (ПОСЛЕ блокировки один и перед проверкой соответствия типа уведомления с использованием динамического преобразования типов), я предполагаю, что это ДОЛЖНО всегда вызывать взаимоблокировку при отправке уведомления из обработчика уведомлений, поскольку он также попытается получить доступ к наблюдателю, откуда он вызывается, и будет бесконечно ждать блокировки в NObserver :: notify ()?
Судя по примерам процесса, которые прислали мне пользователи, мое предположение выглядит правильным.
Но по какой-то причине в большинстве случаев это не заходит в тупик (я сам никогда этого не испытывал). Я только что прошел с отладчиком и не смог его заблокировать. У кого-нибудь есть объяснение, почему это блокируется только при определенных обстоятельствах?