Тупик при отправке уведомления в обработчике уведомлений с помощью Poco :: NotificationCenter - PullRequest
0 голосов
/ 11 января 2019

Я использую 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 ()? Судя по примерам процесса, которые прислали мне пользователи, мое предположение выглядит правильным.

Но по какой-то причине в большинстве случаев это не заходит в тупик (я сам никогда этого не испытывал). Я только что прошел с отладчиком и не смог его заблокировать. У кого-нибудь есть объяснение, почему это блокируется только при определенных обстоятельствах?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...