
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.60] |
![]() |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
![]() |
|
|
решил разобраться с вызовом функций WinApi в асинхронном режиме.
покурил msdn, накидал такой примерчик: ![]() ![]() procedure TForm1.DoAsyncLoad(); var lReaded: Cardinal; lTransferred: Cardinal; lBuff: Pointer; lRes: Boolean; lErr, lErr2: Cardinal; lFileHandle: Cardinal; lOverlapped: TOverlapped; begin lFileHandle := CreateFile( PChar( edtFileName.Text ), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0 ); if lFileHandle = INVALID_HANDLE_VALUE then RaiseLastOSError; try lReaded := 0; ZeroMemory( @lOverlapped, SizeOf( TOverlapped )); GetMem( lBuff, C_BLOCK_SIZE ); //используем большой буфер try repeat lReaded := 0; //обнуляем внутренние данные для нового вызова "перекрываемой" функции lOverlapped.Internal := 0; lOverlapped.InternalHigh := 0; //hEvent не задаю, так как нигде ожидать ничего не будем lRes := ReadFile( lFileHandle, lBuff^, C_BLOCK_SIZE, lReaded, @lOverlapped ); if not lRes then lErr := GetLastError else lErr := ERROR_SUCCESS; if not lRes then begin //обрабатываем случаи, когда ReadFile = False case lErr of //проверка ощибки ReadFile ERROR_IO_PENDING: //асинхронная операция begin lTransferred := 0; repeat lRes := GetOverlappedResult( lFileHandle, lOverlapped, lTransferred, False ); if not lRes then lErr2 := GetLastError; if not lRes then case lErr2 of //проверка ошибки GetOverlappedResult ERROR_IO_INCOMPLETE: Application.HandleMessage; //операция не завершилась? обработаем очередное сообщение ERROR_HANDLE_EOF: begin //файл кончился? lReaded := 0; //ничего не прочитали break; //выходим из внутреннего цикла end; else RaiseLastOSError; end; until lRes; //пока не завершиться операция... if lRes then lReaded := lTransferred; //надо ли? end; ERROR_HANDLE_EOF: lReaded := 0; //если файл кончилсо, то выходим из цикла else RaiseLastOSError; end; end;//конец ветки, когда ReadFile = false if lRes then //здесь мы оказываемся в 2х случаях:1.ReadFile=true; 2.GetOverlappedResult в конце концов тоже вернул True begin // //что-то делаем с lBuff // lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем end; until lReaded = 0; finally FreeMem( lBuff ); end; finally CloseHandle( lFileHandle ); end; end; все бы ничего... да только не всегда получается асинхронный вызов. в случае попытки чтения большого файла с винчестера функция FileRead ждет окончания чтения и возвращает true ( и только в случае первой попытки обращения к съемному носителю срабатывает часть кода по работе с GetOverlappedResult... объясните знающие люди, в чем соль?! |
Сообщ.
#2
,
|
|
|
неплохая статья про асинхронный ввод-вывод.
|
Сообщ.
#3
,
|
|
|
Ahilles Спасибо конечно, но ничего нового статья мне не рассказала. вся информация есть в MSDN.
да и примеры там все с флопом. |
Сообщ.
#4
,
|
|
|
Цитата MetalFan @ все бы ничего... да только не всегда получается асинхронный вызов. Вернее - работает не пойми как. ![]() Цитата MetalFan @ И?? Как же так - пытаешься использовать асинхронное чтение, а главный "семафор окончания отложенной операции" не создаешь? Далее :![]() ![]() //hEvent не задаю, так как нигде ожидать ничего не будем lRes := ReadFile( lFileHandle, lBuff^, C_BLOCK_SIZE, lReaded, @lOverlapped); Цитата MetalFan @ Это не ошибка - это признак того, что отложенная операция нормально стартовала. Здесь бы лучше запустить таймер и по его срабатыванию проверять - закончилась ли операция чтения (считано ли требуемое в ReadFile количество байт (WaitForSingleObject на эвент Overlapp'a должен вернуть WAIT_OBJECT_0 - если нет - то по GetOverlappedResult смотрим, сколько считано и сравниваем с размером файла, или по флагу ERROR_HANDLE_EOF принимаем решение сбросить дальнейшее чтение). Но лучше в любом случае перед считыванием получить размер файла, чтобы знать наверняка, сколько читать.) ![]() ![]() if not lRes then case lErr of //проверка ощибки ReadFile ERROR_IO_PENDING: //асинхронная операция |
Сообщ.
#5
,
|
|
|
Цитата medved_68 @ И?? Как же так - пытаешься использовать асинхронное чтение, а главный "семафор окончания отложенной операции" не создаешь? создавать и использовать его не обязательно. но даже его создание и использование положения не меняет. Цитата medved_68 @ Это не ошибка - это признак того, что отложенная операция нормально стартовала. отложенная операция удачно "стартовала" только если GetLastError вернул ERROR_IO_PENDING. да, это не ошибка по сути. Цитата medved_68 @ сколько считано и сравниваем с размером файла как ты заметил, файл читается не целиком, а кускакми з.ы. ты бы проверил работу кода, ибо пока ничего неясного ты не прояснил. |
Сообщ.
#6
,
|
|
|
M MetalFan, я ваш вопрос отредактировал, код не подсвечивался. Там в теге CODE было CODE=delphi, а нужно - CODE=pas, ну это так, на будущее. Что касается вопроса - думаю, не нужно вызывать Application.HandleMessage; так как эта процедура в конце вызывает засыпание потока на неопределенное время - пока в очередь не поступит сообщение (Idle из которого вызывается WaitMessage). Как обрабатывать сообщения и одновременно дожидаться окончания ввода/вывода гляньте здесь: DeviceIOControl Там вся соль в функции MsgWaitForMultipleObjects |
Сообщ.
#7
,
|
|
|
Rose Сорри, с винграда скопировал и не заметил ньюанса с pas.
по ссылке счас почитаю, спасибо Добавлено Цитата Rose @ так как эта процедура в конце вызывает засыпание потока возможно... но не в этом проблема... если отрабатывает часть кода при FileRead = 0(False), то все ок. видимо я не совсем ясно расписал ситуацию и ты меня не понял ![]() |
Сообщ.
#8
,
|
|
|
Цитата возможно... но не в этом проблема... Все же попробуй переделать свой код на менер того, как в приведенной ссылке - Event заведи, MsgWaitForMultipleObjects используй, ProcessMessages вместо HandleMessage, все должно работать. |
Сообщ.
#9
,
|
|
|
Rose Да нет! ты не понял... ветка кода с GetOverlappedResult и так работает на "ура"! но просто при чтении с ЖД FileRead всегда возвращает true.
при чем тут переделка кода? |
Сообщ.
#10
,
|
|
|
Цитата Rose Да нет! ты не понял... Видимо действительно не понял. Вторая попытка ![]() |
Сообщ.
#11
,
|
|
|
Rose можно на "ты"? ) а то "ты мне тут не выкайте")
Цитата Rose @ ReadFile не обязана вернуть код ошибки ERROR_IO_PENDING именно! в коде обрабатываются оба варианта операции... блин, наверное не очень его красиво структурировал... дополнил код комментариями. Цитата Rose @ Может у Вас именно этот случай? Или на ReadFile код надолго останавливается? у меня именно этот случай при работе с HDD!!!! как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки... |
Сообщ.
#12
,
|
|
|
Цитата Rose можно на "ты"? ) а то "ты мне тут не выкайте") Привычка от других форумов, где принято на "Вы" ![]() Попробую твой код в ближайшее время, пока сам не увижу - наверное не пойму в чем проблема. |
Сообщ.
#13
,
|
|
|
Rose угу, пасип.
да проблемы даже можно сказать и нет... Цитата MetalFan @ как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки... |
Сообщ.
#14
,
|
|
|
Цитата как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки... В общем, мои исследования привели меня к выводу, что все дело в кешировании файлов. Если флаг FILE_FLAG_NO_BUFFERING не установлен, то первое обращение к файлу может занять несколько большее время, а последующие происходят значительно быстрее. Если установлен - то механиз кеширования не применяется, однако при этом нужно соблюсти некоторые требования, о которых в справке написано. Короче, то, что у тебя происходит - это нормальное поведение. |
Сообщ.
#15
,
|
|
|
Цитата Rose @ Если флаг FILE_FLAG_NO_BUFFERING не установлен проверял и с ним и без него. но еще один ньюанс у меня возник (с FILE_FLAG_NO_BUFFERING) - получаю Invalid Parameter вместо ERROR_HANDLE_EOF по достижению конца файла... Добавлено брр... возможно я не учел замечания в msdn по поводу выделения памяти под буфер |