На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Страницы: (6) [1] 2 3 ...  5 6 все  ( Перейти к последнему сообщению )  
    > I/O Completition Port проблемы с удалением OVERLAPPED объектов
      Ситуация такая - есть объект унаследованный от OVERLAPPED, который ассоциируется портом завершения.

      Я столкнулся с ситуацией разрулить которую никак не могу:
      объекты уходят на удаление в двух случаях:
      - GetQueuedCompletionStatus вернул FALSE или *lpNumberOfBytes вернулось ноль
      - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут

      Схема удаления объекта выглядит так:
      - все что подлежит удалению заносится в список на удаление.
      - по тику таймера этот список проверяется
      - если у объекта из списка макрос HasOverlappedIoCompleted возвращает FALSE такой объект не удаляется, список проверяется дальше.
      - если HasOverlappedIoCompleted возвращает TRUE то сначала закрывается сокет ( вызов closesocket ) и потом удаление самого объекта и стирание его из списка.

      проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE
      вызов CancelIO не помогает.
        А если через GetQueuedCompletionStatus попробовать?
          Цитата progman @
          вызов CancelIO не помогает.

          CancelIO надо вызывать из того же потока, который эту IO инициировал.

          Добавлено
          И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки.

          Добавлено
          Цитата progman @
          проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE

          Это скорее всего клиенты с невыполненным WSARecv() на сервере, которые не торопятся слать байты, или вообще отвалились.
          Сообщение отредактировано: Pacific -
            Цитата shm @
            А если через GetQueuedCompletionStatus попробовать?

            Она крутится в рабочем потоке. не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса.

            Цитата Pacific @
            CancelIO надо вызывать из того же потока, который эту IO инициировал.

            я в курсе. и есть еще CancelIOEx
            но все равно не решает проблему (

            Цитата Pacific @
            И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки.

            Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.
            в общем начинается адЪ с многопоточностью - я отказался от этого и закрываю сокет непосредственно перед удалением объекта
            Сообщение отредактировано: progman -
              Цитата progman @
              не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса.

              Почему?
                Цитата progman @
                в частности оъект на удаление может и дважды и трижды попасть в список.

                Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список.
                  Цитата Pacific @
                  Цитата progman @
                  в частности оъект на удаление может и дважды и трижды попасть в список.

                  Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список.

                  ситуация:
                  внутри объекта произошла ошибка и он помещается в список на "расстрел" при этом вызывается закрытие сокета
                  далее три варианта:
                  - все будет нормально и объект удалится без последствий для системы и вызов GetQueuedCompletionStatus не произойдет
                  - после закрытия сокета но до момента удаления сработает GetQueuedCompletionStatus и выдаст что у этого объекта ноль байт в приемнике и он снова будет помещен в очередь на удаление
                  - после закрытия сокета и после удаления сработает GetQueuedCompletionStatus и выдаст или ошибку по этому объекту или то что у него в приемнике ноль байт и уже удаленный объект будет помещен в очередь на удаление
                  Сообщение отредактировано: progman -
                    Цитата progman @
                    Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.

                    А пометить его никак нельзя?
                      Цитата shm @
                      Цитата progman @
                      Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список.

                      А пометить его никак нельзя?

                      что значит пометить? факт помещения объекта в очередь на удаление разве не метка?
                      или имеется ввиду после удаление хранить его адрес в списке удаленных?

                      вся проблема исключительно в том что закрытие сокета у объекта иногда приводит иногда не приводит к срабатыванию GetQueuedCompletionStatus в рабочем потоке для этого объекта.
                      Сообщение отредактировано: progman -
                        Цитата progman @
                        факт помещения объекта в очередь на удаление разве не метка?

                        Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет.
                          А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов).

                          Добавлено
                          Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO.
                            Цитата shm @
                            Цитата progman @
                            факт помещения объекта в очередь на удаление разве не метка?

                            Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет.

                            у меня есть хак - есть список всех когда либо созданных в системе объектов
                            после удаления он из списка выбывает. Перед попыткой удалить идет проверка - есть ли объект в списке или нет.

                            жопа в том что после удаления уже нет никакой возможности понять что это повторное удаление объекта

                            Добавлено
                            Цитата Pacific @
                            А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов).

                            Добавлено
                            Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO.

                            чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                            Более того мы можем 10 раз вызвать WSARecv и получить все данные за дин вызов. Как корректно счетчик тогда вести?
                            Сообщение отредактировано: progman -
                              progman
                              HasOverlappedIoCompleted вообще не необходимости использовать. GetQueuedCompletionStatus в любом случае вернет результат операции, либо когда она сама завершится, либо будет отменена из-за closesocket. Кстати, у тебя на один объект только один OVERLAPPED буфер ("объект унаследованный от OVERLAPPED")? Тогда тебе категорически нельзя вызывать любые overlapped операции с объектом, если текущая не завершилась. Может в этом проблема?

                              Добавлено
                              Цитата
                              Any pending overlapped send and receive operations ( WSASend/ WSASendTo/ WSARecv/ WSARecvFrom with an overlapped socket) issued by any thread in this process are also canceled. Any event, completion routine, or completion port action specified for these overlapped operations is performed. The pending overlapped operations fail with the error status WSA_OPERATION_ABORTED.

                              Все должно работать со связкой closesocket -> GetQueuedCompletionStatus. Если не работает - у тебя баг где-то значит.

                              Добавлено
                              Цитата progman @
                              Более того мы можем 10 раз вызвать WSARecv и получить все данные за дин вызов. Как корректно счетчик тогда вести?

                              Тогда GetQueuedCompletionStatus вернется 10 раз, по одному на каждый вызов. На каждый вызов (если они идут параллельно) надо передавать отдельную структуру OVERLAPPED!
                              Сообщение отредактировано: Pacific -
                                Цитата progman @
                                чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                                Возможно HasOverlappedIoCompleted ненадежно работает поэтому:
                                Цитата
                                Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

                                Особенно для этого случая:
                                Цитата
                                - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут
                                Сообщение отредактировано: Oleg2004 -
                                  Цитата Pacific @
                                  progman
                                  HasOverlappedIoCompleted вообще не необходимости использовать. GetQueuedCompletionStatus в любом случае вернет результат операции, либо когда она сама завершится, либо будет отменена из-за closesocket. Кстати, у тебя на один объект только один OVERLAPPED буфер ("объект унаследованный от OVERLAPPED")? Тогда тебе категорически нельзя вызывать любые overlapped операции с объектом, если текущая не завершилась. Может в этом проблема?


                                  скорее всего в этом - но я не знаю как узнать завершена она или нет.
                                  Вот у меня есть поток в который приходит команда - объект номер 1234 нужно убить.

                                  Как мне дальше правильно поступить?

                                  Добавлено
                                  Цитата Oleg2004 @
                                  Цитата progman @
                                  чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ?

                                  Возможно HasOverlappedIoCompleted ненадежно работает поэтому:
                                  Цитата
                                  Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

                                  да. но как мне гарантированно знать что закрывать сокет можно и объект можно убивать?
                                  чтобы не произошел при этом вызов GetQueuedCompletionStatus

                                  от этого все мои проблемы (
                                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                  0 пользователей:
                                  Страницы: (6) [1] 2 3 ...  5 6 все


                                  Рейтинг@Mail.ru
                                  [ Script execution time: 0,0488 ]   [ 17 queries used ]   [ Generated: 18.04.24, 23:38 GMT ]