Здравствуйте, remark, Вы писали:
R>Здравствуйте, baily, Вы писали:
B>>Есть много разных способов. Например, можно связать с каждым подписчиком класс-защелку. К ней должен иметь доступ как подписчик, так и уведомитель. B>>Защелка открывается в методе Subscribe после добавление подписчика. В методе Unsubscribe она закрывается уведомителем под критической секцией. B>>Класс подписчик в своем методе OnNotification должен вначале проверять, разрешен ли ему вызов. Если нет, то просто выходить.
R>Если он будет просто проверять в начале функции, то мы возвращаемся туда, откуда начали, — может работать нотификация уже отписанного объекта. Ровным счётом ничего не решается.
Я имел ввиду следующее. Надо создать класс-обертку, которая владеет и подписчиком и защелкой.
Она является частью имплементации класса-уведомителя. Обертка тоже имеет метод OnNotification.
Класс-уведомитель хранит массив таких оберток. Когда уведомитель делает рассылку, то он вызывает OnNotification обертки.
Внутри этого метода и проверяется состояние защелки, и только если она открыта, то вызывается OnNotification подписчика.
R>Какие ешё есть разные способы?
Каких то, отличающихся по сути, я не знаю. Везде используется идея защелки. Меняется только ее вид. В предложенном выше случае это просто целочисленный счетчик.
B>>Защелкой должен владеть подписчик. Можно просто создать обертку над подписчиком ( в принципе и умный указатель есть обертка ), который владеет и подписчиком B>>и защелкой. В более сложном варианте можно сделать защелку более сложной, поместив туда еще и событие. При вызове OnNotification, когда защелка открыта, B>>можно увеличивать счетчик использования защелки в начале и уменьшать в конце. А событие взводить, когда счетчик станет равным нулю. Тогда на событии можно ожидать, B>>когда подписчик закончит обрабатывать свой OnNotification.
R>Это потенциальные дедлоки.
Решение рабочее. Дедлоков при аккуратной работе случаться не должно.
Здравствуйте, baily, Вы писали:
R>>Если он будет просто проверять в начале функции, то мы возвращаемся туда, откуда начали, — может работать нотификация уже отписанного объекта. Ровным счётом ничего не решается.
B>Я имел ввиду следующее. Надо создать класс-обертку, которая владеет и подписчиком и защелкой. B>Она является частью имплементации класса-уведомителя. Обертка тоже имеет метод OnNotification. B>Класс-уведомитель хранит массив таких оберток. Когда уведомитель делает рассылку, то он вызывает OnNotification обертки. B>Внутри этого метода и проверяется состояние защелки, и только если она открыта, то вызывается OnNotification подписчика.
Проверяем состояние защелки — она открыта, начинаем выполнение OnNotification подписчика. В это время другой поток отписывает объект. Первый поток продолжает выполнение OnNotification подписчика, когда объект уже отписан. Вернулись туда, откуда начали. Ничего не решено.
Здравствуйте, remark, Вы писали:
R>Проверяем состояние защелки — она открыта, начинаем выполнение OnNotification подписчика. В это время другой поток отписывает объект. Первый поток продолжает выполнение OnNotification подписчика, когда объект уже отписан. Вернулись туда, откуда начали. Ничего не решено.
С тем же успехом можно убрать эту зашёлку. Наличие объекта в списке уже выполняло роль этой защёлки. Но проблема в том, что обе эти проверки происходят только до начала работы метода, в то время как они должны распространять своё действие на всё время работы метода, если мы хотим, что бы он гарантированно не выполнялся после отписки.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Ryadovoy, Вы писали:
R>>Можно попробовать ожидать завершение текущего уведомления в функции Unsubscribe, но тогда скорей всего будут зависания при отключении. R>>Я пока что не нашел подходящее решение с реализацией Unsubscribe, гарантирующей прекращение нотификаций после выхода. R>>Если есть какие-то идеи по этому поводу, буду рад услышать.
R>Ещё один вариант решения — трактовать unsubscribe() не как отписку, а как старт асинхронной отписки, а завершение отписки происходит, когда объект получает вызов release(). Т.е. поток вызывает unsubscribe(), этим от говорит, что он хочет инициировать отписку; но никакой код, которы должен отработать только после завершения отписки, он ещё не вызывает. Потом (или возможно сразу) объекту поступает вызов release(), который говорит о том, что отписка завершена, и теперь уже никаких вызовов объекту точно поступать не будет, теперь можно вызывать код, который должен отработать только после завершения отписки.
R>
Я лично именно так бы и сделал, если бы сам писал.
gh2>1) корректно разрешите проблему безопасности исключений gh2>2) избавитесь от связи (время жизни диспетчера) == (время, проведенное в критической секции) gh2>3) гарантируете отсутствие утечки ресурса "объект-синхронизации" (сейчас это критическая секция)
И как я понимаю получится подмножество библиотеки boost::signals2. Signals2 удобнее ещё тем что не надо реализовывать какой-то интерфейс для создания подписчиков. Подписчиком может быть функция, метод класса или функтор, можно использовать так же bind, что очень удобно в некоторых случаях.
Я очень много раз встречал отказ использовать исключения просто потому что люди не понимаю, как строит программы с обработкой ошибок на исключениях. На вопрос, в чём преимущество обработки ошибок через коды возврата, обычно некоторое время думают и говорят, мол типа один знакомый программист Вася, говорил что исключения тормозные, ну и как-то они запутывают код. Вы понимаете что такое ответ говорит лишь о том что человек не понимает исключений, не понимает как ими пользоваться, за предыдущее время работы не попытался их понять и научится ими пользоваться. И кстати если это время больше 2-х лет, то не стоит связываться с таким человеком и брать его на работу.
Лишь один раз я слышал действительно мотивированный отказ от построения обработки ошибок на исключениях, и это google code convention. Они отказываются от исключений в основном потому, что на момент написания code guidelines у них уже написано огромное количество кода с обработкой ошибок на кодах возврата. При этом перед этим идёт честное сравнение плюсов и минусов обеих подходов.
Здравствуйте, remark, Вы писали:
R>Здравствуйте, baily, Вы писали:
R>>>Если он будет просто проверять в начале функции, то мы возвращаемся туда, откуда начали, — может работать нотификация уже отписанного объекта. Ровным счётом ничего не решается.
B>>Я имел ввиду следующее. Надо создать класс-обертку, которая владеет и подписчиком и защелкой. B>>Она является частью имплементации класса-уведомителя. Обертка тоже имеет метод OnNotification. B>>Класс-уведомитель хранит массив таких оберток. Когда уведомитель делает рассылку, то он вызывает OnNotification обертки. B>>Внутри этого метода и проверяется состояние защелки, и только если она открыта, то вызывается OnNotification подписчика.
R>Проверяем состояние защелки — она открыта, начинаем выполнение OnNotification подписчика. В это время другой поток отписывает объект. Первый поток продолжает выполнение OnNotification подписчика, когда объект уже отписан. Вернулись туда, откуда начали. Ничего не решено.
R>
Гм! Согласен. Я поторопился. У меня в коде решение, использующее ту же идею, что у вас в этом
Здравствуйте, TarasKo, Вы писали:
TK>Лишь один раз я слышал действительно мотивированный отказ от построения обработки ошибок на исключениях, и это google code convention. Они отказываются от исключений в основном потому, что на момент написания code guidelines у них уже написано огромное количество кода с обработкой ошибок на кодах возврата. При этом перед этим идёт честное сравнение плюсов и минусов обеих подходов.
Android NDK, например, не поддерживает исключения и RTTI. Во что превращается портирование кода в случае, если ты их используешь, думаю объяснять не надо ))
Здравствуйте, COFF, Вы писали:
COF>Здравствуйте, TarasKo, Вы писали:
TK>>Лишь один раз я слышал действительно мотивированный отказ от построения обработки ошибок на исключениях, и это google code convention. Они отказываются от исключений в основном потому, что на момент написания code guidelines у них уже написано огромное количество кода с обработкой ошибок на кодах возврата. При этом перед этим идёт честное сравнение плюсов и минусов обеих подходов.
COF>Android NDK, например, не поддерживает исключения и RTTI. Во что превращается портирование кода в случае, если ты их используешь, думаю объяснять не надо ))
Исключения там не поддерживаются, потому что в Google их не используют. А не используют, потому что coding conventions такие. Иначе бы давно сделали. Это не так уж и сложно, как показывает следующий проект: http://www.crystax.net/android/ndk-r4.php
Здравствуйте, alexeiz, Вы писали:
COF>>Android NDK, например, не поддерживает исключения и RTTI. Во что превращается портирование кода в случае, если ты их используешь, думаю объяснять не надо ))
A>Исключения там не поддерживаются, потому что в Google их не используют. А не используют, потому что coding conventions такие. Иначе бы давно сделали. Это не так уж и сложно, как показывает следующий проект: http://www.crystax.net/android/ndk-r4.php
Это другой вопрос, на самом деле — почему это так? Если ты не гугл, конечно )) Факт, что на настоящий момент код с исключениями значительно менее портабелен, как это ни прискорбно
Здравствуйте, LeonCrew, Вы писали:
LC>Минусы: LC>- дополнительный расход памяти на дополнительные списки (к каким издателям подписан подписчик), для встраиваемых систем может быть критично;
У меня есть идея что при определенном подходе в написании кода, который использует эту схему, такие списки на стороне подписчиков становятся лишними. Однако я пока не доказал даже для себя что это возможно. Также не видел противоположного доказательства.