Здравствуйте, Armastab, Вы писали:
A>Происходит "преждевременное" срабатывание обработчика — вызов WSARecv еще не завершен.
Нету никаких "преждевременных" срабатываний. Ищи ошибки.
Re[7]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Gomes, Вы писали:
G>Здравствуйте, Armastab, Вы писали:
A>>Странность в том, что срабатывание обработчика, по моему мнению, происходит до того, как WSARecv/WSASend закончили свою работу и вернули управление в вызывающий их поток. Т.к. WSARecv/Send еще не отработал до конца, а OVERLAPPED уже рарзушено в другом процессе внезапно сработавшим обработчиком, возникает исключение. G>Ерунда. Обработчик вызывается только после завершения WSARecv/WSASend, иначе быть не может. Может тебе так кажется на двух ядрах? G>В обработчике можешь смело удалять структуру. Если вылазит ошибка — ищи баг.
Ну, собственно говоря, мой вопрос и преследовал цель выяснить, это мне так кажется на двух ядрах ( к этому варианту я изначально и склонялся) или, действительно, такое явление в природе существует.
Изначально я был уверен, что где-то у меня глюки, но после ответа Michael Chelnokov стал думать, что такая ситуация (с преждевременным срабатыванием обработчика) случается и надо просто принимать ее как нормальное явление и работать с ней через защиту объектов от преждевременного удаления
Re[6]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Armastab, Вы писали:
A>Ну, собственно говоря, мой вопрос и преследовал цель выяснить, это мне так кажется на двух ядрах ( к этому варианту я изначально и склонялся) или, действительно, такое явление в природе существует.
20 постов непонятно для чего. Надо спрашивать прямо и понятно, так же и ответят
Re[8]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Armastab, Вы писали:
A>Изначально я был уверен, что где-то у меня глюки, но после ответа Michael Chelnokov стал думать, что такая ситуация (с преждевременным срабатыванием обработчика) случается и надо просто принимать ее как нормальное явление и работать с ней через защиту объектов от преждевременного удаления
нормальное явление ???? где это описано, это из разряда "наши гранаты супер, но каждая 20я взрывается в руках " ..,
вот б ссылочку на MS — описание бага и методы борьбы
Re[7]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Pepel, Вы писали:
P>да, к слову , а код возврата WSARecv какой в таком раскладе ?
Не понял, при каком раскладе? Стандартно ERROR_IO_PENDING.
Re[7]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, xentry, Вы писали:
X>Здравствуйте, Pepel, Вы писали:
P>>и как в такой ситуации помогают некие счетчики ссылок — я понимаю есть псевдосрабатывание завершения некой асинхронной операции, которое тем и отличается от настоящего, что находится на самом деле еще в работе и посему одновременное обращение к конструкциям данного асинхронного вызова вызывает нарушение доступа
X>Скорее всего там нет никакого псевдосрабатывания — я думаю что топикстартер не разобрался доконца в механизме работы. Счетчик ссылок может помочь например при закрытии сокета — т.к. это может вызвать завершение асинхронных операций (если они конечно были).
P>>тогда только в __try — catch() брать обработчик завершения отсылки/получения и если ловим ACCESS_VIOLATION — игнорируем его, полагая , что код вменяемый и нарушение доступа по иной причине маловероятно
X>В обрабочике ловить ACCESS_VIOLATION будет поздно — приложение к этому моменту уже вылетит в отладчик.
Ага, попробовал — там тоже не ловится. Этого следовало ожидать, но я уже согласен на любый идеи, которые могут как-то помочь разобраться в ситуации
Re[7]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Pepel, Вы писали:
P>да, к слову , а код возврата WSARecv какой в таком раскладе ?
В ситуациях без исключения SOCKET_ERROR, WSA_IO_PENDING, а когда возникает исключение, то никакого кода возврата нет, т.к.WSARecv разорвало исключением.
Re[8]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Pepel, Вы писали:
P>я к слову вот overlapped не разрушаю, а обнуляю на обработчике завершения (memeset(..))
P>а вообщем чтот здесь странно , я так понял у вас это не редкость — такая ситуевина, тогда это черти че , мож патчи накатайте на операционку
Я проводил тестирование на нескольких не моих серверах на IOCP — там такой ошибки не возникает, но ни один из них не разрушает OVERLAPPED. Во всех реализовано повторное использование памяти, т.е. те же структуры отправляются в очередь свободных структур и обнуляются при последющем использовании. Я тоже собираюсь в будущем так сделать, но, как мне кажется, это вылечит следствия проблемы, а не ее причину, т.к. если у меня где-то есть ошибка, то она останется, просто будет реализован механизм защиты от ее последствий.
Патчи...винда каждый день скачивает кучу какого-то барахла и устанавливает, так что, мне кажется, что все последние обновления присутствуют
Anyway, спасибо за советы
Re[3]: Исключение Access violation в WSASend и WSARecv (IOCP
вот поднял исходники, у меня исключительно под отладчиком происходило псевдосрабатывание GetQueuedCompletionStatus() и именно когда рабочих потоков более одного,
при этом @err = 87 (ERROR_INVALID_PARAMETER)
фенька была именно под отладчиком, но вот бодался пока не сообразил
Re[4]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Pepel, Вы писали:
P>вот поднял исходники, у меня исключительно под отладчиком происходило псевдосрабатывание GetQueuedCompletionStatus() и именно когда рабочих потоков более одного,
P> при этом @err = 87 (ERROR_INVALID_PARAMETER)
P> фенька была именно под отладчиком, но вот бодался пока не сообразил
Под отладчиком у меня такой ошибки не возвращается.
А вот без отладчика, исключение вроде бы не возникает (уже минут 20 как работает без вылетов), хотя попытки удалять защищенный объект в логе фиксируются, но возможно это происходит потому, что обрабочик активизируется сразу после асинхронного вызова, до выполнения команды разблокировки объекта.
Спасибо.
Re[9]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, Pepel, Вы писали:
P>нормальное явление ???? где это описано, это из разряда "наши гранаты супер, но каждая 20я взрывается в руках " .., P>вот б ссылочку на MS — описание бага и методы борьбы
Никаких ошибок, вполне штатная ситуация. Где написано, что WSARecv/WSASend должны выполняться атомарно со следующей строкой на C?
С точки зрения ядра начало операции ввода/вывода уже прошло. Ядро не интересует, выполнилась ли уже на пользовательском уровне инструкция ret, или следующий за ней код.
Re[10]: Исключение Access violation в WSASend и WSARecv (IOC
я так понял : асинхронная операция, инициируемая вызовом WSARecv/WSASend, может завершиться РАНЬШЕ, чем сама функция WSARecv/WSASend вернет управление и по этой причине обработчик завершения может грохнуться , ну понятно почему
это реально правда ?
но тогда какие счетчики ? нужна синхронизация полноценная , евенты теж — выставляем евент по возврату из WSARecv/WSASend , а на обработчике завершения ждем пока евент в UP не станет
...
и вообщем странно, что такие .. не ну гвозди .. и нигде не описаны
Re[11]: Исключение Access violation в WSASend и WSARecv (IOC
Здравствуйте, Pepel, Вы писали:
P>я так понял : асинхронная операция, инициируемая вызовом WSARecv/WSASend, может завершиться РАНЬШЕ, чем сама функция WSARecv/WSASend вернет управление
Да.
P>и по этой причине обработчик завершения может грохнуться , ну понятно почему
Грохнуться может неправильно реализованный обработчик.
P>это реально правда ?
Да, вполне. Это ошибка — предполагать, что обработчик будет вызван позже, чем следующая за WSARecv/WSASend инструкция.
P>но тогда какие счетчики ? нужна синхронизация полноценная , евенты теж — выставляем евент по возврату из WSARecv/WSASend , а на обработчике завершения ждем пока евент в UP не станет
TMTOWTDI. Я лишь привел один из возможных способов, который годится для описанной Armastab ситуации. Ему ведь главное — не удалить объект CIOReq преждевременно.
P>и вообщем странно, что такие .. не ну гвозди .. и нигде не описаны
Они следуют из общей архитектуры системы, причем любой современной системы. Возврат из системного вызова происходит не мнгновенно, и за это время в другом потоке может много чего произойти.
Re: Исключение Access violation в WSASend и WSARecv (IOCP)
Здравствуйте, Armastab, Вы писали:
A>Добрый день, A>Заранее спасибо.
у вас ещё больше проблемм чем вы думаете.
для начала, зачем все время делать new и delete для буферов? именно из-за такой модели у вас и куча проблемм.
сделайте пул, или возьмите тот-же SLIST http://msdn.microsoft.com/en-us/library/ms686309(VS.85).aspx
запихайте в него new CIOReq'ов столько сколько нужно для полной загрузки
и когда надо берите из пула буфер, и после обработки возвращайте буфер в пул.
итого нету жрущих проц new delete, и никаких access viloation
Re[2]: Исключение Access violation в WSASend и WSARecv (IOCP
Здравствуйте, maxlosyam, Вы писали:
M>Здравствуйте, Armastab, Вы писали:
A>>Добрый день, A>>Заранее спасибо.
M>у вас ещё больше проблемм чем вы думаете. M>для начала, зачем все время делать new и delete для буферов? именно из-за такой модели у вас и куча проблемм.
спасибо, что обратили внимание. Я знаю про эту проблему и следующим шагом как раз собирался реализовать повторное использование памяти, просто пока отлаживал именно в вышеописанном варианте.
Re: Исключение Access violation в WSASend и WSARecv (IOCP)
От:
Аноним
Дата:
01.07.09 16:48
Оценка:
Здравствуйте, Armastab, Вы писали:
A>Добрый день, A>Я столкнулся со следующей проблемой. Есть TCP-сервер построенный на технологии портов завершения ввода-вывода. Есть 20 клиентов, которые в целях тестирования непрерывно выполняют следующие команды: Connect, Send (3байта), Disconnect. Клиенты запущены на той же машине, что и сервер.
A>Основная функция рабочего потока сервера выглядит стандартно для IOCP, примерно так:
A>void WorkerThread::Run() A>{
A> ... A> while(true) A> { A> ... A> fOk = m_refIOCP.GetStatus(&CompKey,&dwNumBytes, (OVERLAPPED**)&pIOReq); A> ... A> HandleOperation(CompKey, pIOReq, dwNumBytes); A> ... A> delete pIOReq; A> .. A> } A> ... A>}
A>Есть класс CIOReq наследованный от OVERLAPPED, который несет дополнительную информацию об операциях. A>Функция HandleOperation имеет некоторую логику и делает следующие вызовы:
A>1. A>... A>pIOReq = new CIOReq(); A>... A>int nRes = WSASend(socket, pWSABUF , 1, &dwLen, dwFlags, (OVERLAPPED*)pIOReq, NULL);
A>2. A>... A>pIOReq = new CIOReq(); A>... A>nRes = WSARecv(socket, pWSABUF, 1, &dwSize, &dwFlags,(OVERLAPPED*)pIOReq , NULL);
A>Иногда (при указанной нагрузке 20 клиентов, в среднем раз в 30 секунд, иногда чаще, иногда реже), WSASend и WSARecv вываливаются с исключением 0x00000005 Access violation. A>При этом поля класса pIOReq оказываются невалидными, как будто объект удален. Данное исключение выскакивает в отладчике и не перехватывается ни try-catch ни __try — __except
A>Экспериментально выяснилось, если количество рабочих потоков сделать равным 1 (обычно запущено 10), такой ошибки не возникает. A>Если сделать защиту (собственный механизм) указателя pIOReq от удаления, до возврата из WSASend, WSARecv, то ошибки тоже не возникает, а отлавливается попытка удалить объект до снятия защиты.
A>Из всего вышеописанного у меня сложилось ощущение, что один из ожидающих рабочих потоков получает управление и сигнал о завершении ввода-вывода, еще до того как произошел возврат из WSASend WSARecv. A>Он удаляет объект pIOReq и в WSASend/WSARecv происходит нарушение доступа.
A>Вопросы: A>как сигнал о завершении ввода-вывода может поступать до завершения асинхронной функции ввода-вывода, A>почему это исключение не отлавливается стандартными средствами обработки исключений A>что с этим делать?
A>Заранее спасибо.
Судя по этим строчкам, вы просто производите удаление объекта pIOReq, который же является OVERLAPPED структурой, до завершения асинхронной операции. А точно знать, что она завершилась, можно тогда, когда WSASend() вернула 0, или установилось событие hEvent из переданной OVERLAPPED структуры, или был бы вызван обработчик завершения lpCompletitionRoutine(), который бы устанавливался последним параметром WSASend(), но вы его не устанавливаете. Очевидно, до удаления указателя надо проверить код возврата и статус операции и, если она была отложенной, ждать события завершения...
=)
Re[10]: Исключение Access violation в WSASend и WSARecv (IOC
От:
Аноним
Дата:
01.07.09 18:20
Оценка:
Здравствуйте, Michael Chelnokov, Вы писали: MC>Никаких ошибок, вполне штатная ситуация. Где написано, что WSARecv/WSASend должны выполняться атомарно со следующей строкой на C? MC>С точки зрения ядра начало операции ввода/вывода уже прошло. Ядро не интересует, выполнилась ли уже на пользовательском уровне инструкция ret, или следующий за ней код.
Мда, открываются новые аспекты...
Возможно теперь я разберусь, почему у меня иногда валится приложение, несмотря на попытку сохранять буферы подсчетом ссылок.
Насколько я понял, схема должна быть приблизительно такая:
void WorkerThread::Run(){
while( true ){
fOk = m_refIOCP.GetStatus( &CompKey, &dwNumBytes, (OVERLAPPED**)&pIOReq );
HandleOperation( CompKey, pIOReq, dwNumBytes );
// если функция WSASend/WSARecv вернула управление до того,
// как система обработала запрос и переключилась в поток обработчика - удаление,
// иначе - уменьшение счетчика
pIOReq->Release();
}
}
...
void HandleOperation(...){
...
pIOReq = new CIOReq();
// дважды увеличиваем счетчик ссылок
pIOReq->AddRef(); // соответсвует Release() после WSASend()
pIOReq->AddRef(); // соответсвует Release() после HandleOperation()int nRes = WSASend( socket, pWSABUF , 1, &dwLen, dwFlags, (OVERLAPPED*)pIOReq, NULL );
// если HandleOperation вернула управление, обработав операцию раньше возврата
// из асинхронной функции - удаление, иначе - уменьшение счетчика
pIOReq->Release();
...
pIOReq = new CIOReq();
pIOReq->AddRef();
pIOReq->AddRef();
nRes = WSARecv( socket, pWSABUF, 1, &dwSize, &dwFlags,(OVERLAPPED*)pIOReq , NULL );
// если HandleOperation вернула управление, обработав операцию раньше возврата
// из асинхронной функции - удаление, иначе - уменьшение счетчика
pIOReq->Release();
...
}
?
Re[11]: Исключение Access violation в WSASend и WSARecv (IOC
От:
Аноним
Дата:
01.07.09 18:31
Оценка:
забыл добавить:
void HandleOperation(...){
...
pIOReq = new CIOReq();
// дважды увеличиваем счетчик ссылок
pIOReq->AddRef(); // соответсвует Release() после WSASend()
pIOReq->AddRef(); // соответсвует Release() после HandleOperation()int nRes = WSASend( socket, pWSABUF , 1, &dwLen, dwFlags, (OVERLAPPED*)pIOReq, NULL );
if (nRes == SOME_ERROR && nRes != IO_PENDING)
pIOReq->Release();// если HandleOperation вернула управление, обработав операцию раньше возврата
// из асинхронной функции - удаление, иначе - уменьшение счетчика
pIOReq->Release();
...
pIOReq = new CIOReq();
pIOReq->AddRef();
pIOReq->AddRef();
nRes = WSARecv( socket, pWSABUF, 1, &dwSize, &dwFlags,(OVERLAPPED*)pIOReq , NULL );
if (nRes == SOME_ERROR && nRes != IO_PENDING)
pIOReq->Release();// если HandleOperation вернула управление, обработав операцию раньше возврата
// из асинхронной функции - удаление, иначе - уменьшение счетчика
pIOReq->Release();
...
}