Текущий архив: 2007.05.20;
Скачать: CL | DM;
Вниз
Время вызова колбэка FileIOCompletionRoutine Найти похожие ветки
← →
Riply © (2007-05-02 01:04) [0]Здравствуйте !
Дупустим, мы вытворяем следущее:
Вызываемif ReadFileEx(........., @FOverLapRead, pCallBack) then inc(FOverLapRead.hEvent);
с таким колбэком:
procedure Overlapped_CallBack(cbError: DWord; BytesTransf: DWord; pOverLap: POVERLAPPED); stdcall;
begin
with pOverLap^ do
if hEvent = bla-bla then bla-bla-bal
end;
Может ли получиться так, что наш колбэк успеет вызваться до inc(FOverLapRead.hEvent) ?
И аналогичная ситуация при использовании BindIoCompletionCallback.
Мы где-то "за_биндкомлетили" наш хэндл: BindIoCompletionCallback(FhPipe, Overlapped_CallBack, aFlag)
и вызываем:
if ReadFile(......., @FOverLapRead) then inc(FOverLapRead.hEvent);
Такой же вопрос:
Может ли колбэк успеть вызваться до inc(FOverLapRead.hEvent) ?
В случае положительного ответа на любой из этих вопросов, возникает еще один: как с этим бороться ?
P.S.
Я понимаю, что одно из решений: увеличивать hEvent до вызова ReadFile(Ex) и в случае неудачи - уменьшить.
Но я привела упрощенный пример. Вместо inc(FOverLapRead.hEvent) у меня довольно сложные действия,
которые хотелось бы выполнять только в случае успешного вызова ReadFile(Ex).
← →
Riply © (2007-05-02 02:13) [1]После тяжких раздумий, начинаю склоняться к тому, что в первом случае это невозможно,
пока нить-читатель не вызовет MsgWaitForMultipleObjectsEx. Так ли это ?
← →
Riply © (2007-05-02 02:34) [2]>[1] Riply © (02.05.07 02:13)
>в первом случае это невозможно, пока нить-читатель не вызовет MsgWaitForMultipleObjectsEx
Отнюдь не факт. А если вызовы идут из колбека ?procedure Overlapped_CallBack(cbError: DWord; BytesTransf: DWord; pOverLap: POVERLAPPED); stdcall;
begin
if ReadFileEx(........., pOverLap, @Overlapped_CallBack)
then inc(pOverLap.hEvent)
else dec(pOverLap.hEvent);
end;
Совсем запуталась :)
← →
Сергей М. © (2007-05-02 08:17) [3]
> Отнюдь не факт. А если вызовы идут из колбека ?
Именно факт.
Колбек будет вызываться системой в контексте тек.нити (той что вызвала Read/WriteEx) только при нахождении тек.нити в "тревожном" (alertable) состоянии, а оно как раз и наступает в рез-те вызова MsgWaitForMultipleObjectsEx.
← →
Riply © (2007-05-02 09:21) [4]>[3] Сергей М. © (02.05.07 08:17)
Привет :)
>Именно факт.
>Колбек будет вызываться системой в контексте тек.нити (той что вызвала Read/WriteEx)
>только при нахождении тек.нити в "тревожном" (alertable) состоянии,
>а оно как раз и наступает в рез-те вызова MsgWaitForMultipleObjectsEx.
Я, сначала, тоже так подумала, но следущий эксперимент показывает, что это не совсем верно:
Вызваем в нашей нити MsgWaitForMultipleObjectsEx, и, после этого запускаем "рекурсивный" читающий колбэк.
Если организовать "непрерывный поток данных" (сразу отправить, допустим, 100 сообщений по InBufferSize байт),
то наш колбэк самовызовется сто раз и только после этого один(!) раз сработает
MsgWaitForMultipleObjectsEx с результатом WAIT_IO_COMPLETION.
Т.е. колбэк не остановится и не вызовет WAIT_IO_COMPLETION,
пока не обработает (не занаю как назвать) пусть так: "все сообщения в очереди".
Если я правильно понимаю эту ситуацию, один раз вызвав MsgWaitForMultipleObjectsEx,
мы уже перевели нить в тревожное ожидание и, после этого возможны вызовы колбека подряд,
без перерывов на WAIT_IO_COMPLETION и новый вызов MsgWaitForMultipleObjectsEx
← →
Сергей М. © (2007-05-02 10:24) [5]
> сразу отправить, допустим, 100 сообщений по InBufferSize
> байт
А зачем так делать ?
Это же ненормально ...
Если ты отправила сообщение, т.е. вызвала WriteFileEx, ты тем самым запустила асинхронную операцию вывода, о результатах выполнения которой тебе сообщит колбэк, который будет вызван не раньше ближайшего по времени перевода тобой отправляющей нити в трев.сост-е.
Вчитайся внимательно в справку:
If the WriteFileEx function succeeds, the calling thread has an asynchronous I/O (input/output) operation pending: the overlapped write operation to the file. When this I/O operation finishes, and the calling thread is blocked in an alertable wait state, the operating system calls the function pointed to by lpCompletionRoutine, and the wait completes with a return code of WAIT_IO_COMPLETION.
If the function succeeds and the file-writing operation finishes, but the calling thread is not in an alertable wait state, the system queues the call to *lpCompletionRoutine, holding the call until the calling thread enters an alertable wait state
И причем здесь, кстати, отправка, если речь сейчас идет о приеме ?
Для принимающей стороны нет никаких "сообщений", есть просто некий поток входящих данных, из которого она запрашивает для асинхронного чтения нужное кол-во байт. Колбэк-логика же при этом та же самая, что и при отправке.
← →
Riply © (2007-05-02 11:40) [6]>[5] Сергей М. © (02.05.07 10:24)
>> сразу отправить, допустим, 100 сообщений по InBufferSize байт
>А зачем так делать ?
>Это же ненормально ...
Может и ненормально, но я хочу добиться, чтобы сервер мог работать без всяких AV и прочих
"сюрпризов" вне зависимости от того кто, как, что и с какой частотой ему послал.
Ведь это некузяво, если сервер падает из-за клиента :)
Вот и гоняю его в различных условиях.
>И причем здесь, кстати, отправка, если речь сейчас идет о приеме ?
Речь, действительно, идет о приеме. Но чтобы его(прием) проверить, я со стороны клиента посылаю серверу "поток данных"
>Для принимающей стороны нет никаких "сообщений", есть просто некий поток входящих данных,
Значит я рано заявляла, что "с терминологией разобрались" :) Просто я представила себе поток,
состоящим из кусочков по InBufferSize, которые о обозвала "сообщениями".
>Вчитайся внимательно в справку:
Вот и получается, что при использовании "рекурсивного" читающего колбэка, до того как произойдет:
>When this I/O operation finishes, and the calling thread is blocked in an alertable wait state,
>the operating system calls the function pointed to by lpCompletionRoutine, and the wait completes with
>a return code of WAIT_IO_COMPLETION.
наш колбэк самовызывется столько раз, во сколько раз "входящий поток данных" превосходит размер буфера чтения,
без перевода "the calling thread is blocked in an alertable wait state". И только, когда поток данных завершился,
мы получаем однократное WAIT_IO_COMPLETION событие в нити.
Во всяком случае, такую ситуацию я стабильно воспроизвожу, а именно:
многократный вызов колбэка без события WAIT_IO_COMPLETION и повторного вызова MsgWaitForMultipleObjectsEx.
Поэтому САБЖ-евый вопрос остается пока открытым и для ReadFileEx :)
← →
Сергей М. © (2007-05-02 11:52) [7]
> наш колбэк самовызывется столько раз, во сколько раз "входящий
> поток данных" превосходит размер буфера чтения
Ты в теле колбэк-процедуры анализируешь параметр BytesTransf, прежде чем принимать решение об очередном вызове ReadFileEx ?
← →
Riply © (2007-05-02 12:06) [8]> [7] Сергей М. © (02.05.07 11:52)
>Ты в теле колбэк-процедуры анализируешь параметр BytesTransf,
>прежде чем принимать решение об очередном вызове ReadFileEx ?
Да. И dwErrorCode и BytesTransf и еще сравниваю полученные данные с отправленными.
Все сходится(пока :).
← →
Сергей М. © (2007-05-02 12:32) [9]Пусть размер буфера чтения пайпа у тебя равен, к примеру, 4 байтам.
Пусть партнер послал тебе сообщение размером, скажем, 4*4=16 байт.
Пусть ты запросила к асинхронному чтению эти самые 16 байт вызовом ReadFileEx с указанием колбэк-процедуры и перевела нить в трев.состояние.
Тогда у тебя возникнет 4 вызова колбэк-процедуры, в каждом из которых параметр BytesTransf будет равен 4. Ты просто акумулируешь где-то в своем буфере эти 4 раза по 4 байта, при условии что dwErrorCode = 0.
После возврата из 4-го колбэка ты будешь выброшена системой из трев.состояния по событию WAIT_IO_COMPLETION, означающему что:
- либо все запрошенные тобой данные в размере 16-ти байт успешно приняты
- либо операция ввода была отменена вызовом CancelIo[Ex]
Посмотри пример от самих мелкомягких:
http://msdn2.microsoft.com/en-us/library/aa365601.aspx
← →
Riply © (2007-05-02 22:09) [10]>[9] Сергей М. © (02.05.07 12:32)
>Пусть размер буфера чтения пайпа у тебя равен, к примеру, 4 байтам.
>Пусть партнер послал тебе сообщение размером, скажем, 4*4=16 байт.
>Пусть ты запросила к асинхронному чтению эти самые 16 байт вызовом ReadFileEx с указанием
>колбэк-процедуры и перевела нить в трев.состояние.
Запросила то я 4 байта, а вот сколько реально(если рекурсия) прочитаю одному богу да отправителю известно :)
>Тогда у тебя возникнет 4 вызова колбэк-процедуры, в каждом из которых параметр BytesTransf будет равен 4.
>Ты просто акумулируешь где-то в своем буфере эти 4 раза по 4 байта, при условии что dwErrorCode = 0.
>После возврата из 4-го колбэка ты будешь выброшена системой из трев.состояния по событию WAIT_IO_COMPLETION, >означающему что:
>- либо все запрошенные тобой данные в размере 16-ти байт успешно приняты
>- либо операция ввода была отменена вызовом CancelIo[Ex]
Да. Все происходит именно так, как ты описал.
Значит будем считать установленным факт возможности нескольких вызовов колбэка подряд,
без выброса "системой из трев.состояния по событию WAIT_IO_COMPLETION".
А это оставляет САБЖ-вый вопрос актуальным и для ReadFileEx.
Мне, как и тебе, больше нравится рекурсивный метод чтения, но он ставит перед нами еще один вопрос:
Время отклика нашей нити становится непредсказуемым(теоретически, мы можем довольно
долго крутиться в цикле чтения), и пока мы там, нить не реагирует
ни на какие сообщения или события по MsgWaitForMultipleObjectsEx.
А нас (например, сервис менджер) запросил о нашем состоянии
и долго ждать ответа не собирается :) Прибъет ведь ненароком :)
Как бы ухитрится ему ответить в этой ситуации ?
Страницы: 1 вся ветка
Текущий архив: 2007.05.20;
Скачать: CL | DM;
Память: 0.49 MB
Время: 0.033 c