Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.220.27.93] |
|
Страницы: (6) [1] 2 3 ... 5 6 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Ситуация такая - есть объект унаследованный от OVERLAPPED, который ассоциируется портом завершения.
Я столкнулся с ситуацией разрулить которую никак не могу: объекты уходят на удаление в двух случаях: - GetQueuedCompletionStatus вернул FALSE или *lpNumberOfBytes вернулось ноль - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут Схема удаления объекта выглядит так: - все что подлежит удалению заносится в список на удаление. - по тику таймера этот список проверяется - если у объекта из списка макрос HasOverlappedIoCompleted возвращает FALSE такой объект не удаляется, список проверяется дальше. - если HasOverlappedIoCompleted возвращает TRUE то сначала закрывается сокет ( вызов closesocket ) и потом удаление самого объекта и стирание его из списка. проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE вызов CancelIO не помогает. |
Сообщ.
#2
,
|
|
|
А если через GetQueuedCompletionStatus попробовать?
|
Сообщ.
#3
,
|
|
|
Цитата progman @ вызов CancelIO не помогает. CancelIO надо вызывать из того же потока, который эту IO инициировал. Добавлено И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки. Добавлено Цитата progman @ проблема в том что накапливается очень быстро большое число объектов для которых HasOverlappedIoCompleted всегда возвращает FALSE Это скорее всего клиенты с невыполненным WSARecv() на сервере, которые не торопятся слать байты, или вообще отвалились. |
Сообщ.
#4
,
|
|
|
Цитата shm @ А если через GetQueuedCompletionStatus попробовать? Она крутится в рабочем потоке. не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса. Цитата Pacific @ CancelIO надо вызывать из того же потока, который эту IO инициировал. я в курсе. и есть еще CancelIOEx но все равно не решает проблему ( Цитата Pacific @ И да, если закрыть сокет, то все pending IO обязательно отменятся с соответствующим кодом ошибки. Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список. в общем начинается адЪ с многопоточностью - я отказался от этого и закрываю сокет непосредственно перед удалением объекта |
Сообщ.
#5
,
|
|
|
Цитата progman @ не уверен что приемлемо ее вызывать из потока в котором объекты киляются для определения статуса. Почему? |
Сообщ.
#6
,
|
|
|
Цитата progman @ в частности оъект на удаление может и дважды и трижды попасть в список. Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список. |
Сообщ.
#7
,
|
|
|
Цитата Pacific @ Цитата progman @ в частности оъект на удаление может и дважды и трижды попасть в список. Вот с этого и надо начать все разгребать. Простой атомарный флаг "объект в расстрельном списке" решает проблему. Удалось атомарно поменять 0 на 1 - значить можно спокойно вызвать closesocket прямо там же и поместить объект в список. ситуация: внутри объекта произошла ошибка и он помещается в список на "расстрел" при этом вызывается закрытие сокета далее три варианта: - все будет нормально и объект удалится без последствий для системы и вызов GetQueuedCompletionStatus не произойдет - после закрытия сокета но до момента удаления сработает GetQueuedCompletionStatus и выдаст что у этого объекта ноль байт в приемнике и он снова будет помещен в очередь на удаление - после закрытия сокета и после удаления сработает GetQueuedCompletionStatus и выдаст или ошибку по этому объекту или то что у него в приемнике ноль байт и уже удаленный объект будет помещен в очередь на удаление |
Сообщ.
#8
,
|
|
|
Цитата progman @ Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список. А пометить его никак нельзя? |
Сообщ.
#9
,
|
|
|
Цитата shm @ Цитата progman @ Это рождает каскад других побочных проблем - в частности оъект на удаление может и дважды и трижды попасть в список. А пометить его никак нельзя? что значит пометить? факт помещения объекта в очередь на удаление разве не метка? или имеется ввиду после удаление хранить его адрес в списке удаленных? вся проблема исключительно в том что закрытие сокета у объекта иногда приводит иногда не приводит к срабатыванию GetQueuedCompletionStatus в рабочем потоке для этого объекта. |
Сообщ.
#10
,
|
|
|
Цитата progman @ факт помещения объекта в очередь на удаление разве не метка? Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет. |
Сообщ.
#11
,
|
|
|
А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов).
Добавлено Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO. |
Сообщ.
#12
,
|
|
|
Цитата shm @ Цитата progman @ факт помещения объекта в очередь на удаление разве не метка? Ну раз у тебя один и тот же объект 2 раза в очередь попадает, то значит нет. у меня есть хак - есть список всех когда либо созданных в системе объектов после удаления он из списка выбывает. Перед попыткой удалить идет проверка - есть ли объект в списке или нет. жопа в том что после удаления уже нет никакой возможности понять что это повторное удаление объекта Добавлено Цитата Pacific @ А, теперь понятно. В моем типовом коде IOCP сервере есть счетчик pending IO операций. Когда вызываю WSASend/WSARecv/AcceptEx/DisconnectEx, счетчик увеличивается, когда получаю результат через GetQueuedCompletionStatus, счетчик уменьшается. Если счетчик стал равен 0 и объект помечен на удаление, то он удаляется (на самом деле не удаляется, а зачищается от старых данных и помещается в пул свободных объектов). Добавлено Так что просто помечай на удаление, вызывай closesocket + считай, сколько там осталось pending IO. чем это будет отличаться от проверки HasOverlappedIoCompleted которая у меня есть и которая не надежно работает ? Более того мы можем 10 раз вызвать WSARecv и получить все данные за дин вызов. Как корректно счетчик тогда вести? |
Сообщ.
#13
,
|
|
|
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! |
Сообщ.
#14
,
|
|
|
Цитата 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. Особенно для этого случая: Цитата - внутренняя серверная логика приняла решение что клиент должен быть дисконнектнут |
Сообщ.
#15
,
|
|
|
Цитата 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 от этого все мои проблемы ( |