Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2009.05.24;
Скачать: [xml.tar.bz2];

Вниз

ReadFile c Overlapped, ньюансы работы.   Найти похожие ветки 

 
MetalFan ©   (2007-12-16 19:46) [0]

решил разобраться с вызовом функций 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
         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;
       if lRes then
       begin
         //
         //что-то делаем с lBuff
         //
         lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
       end;
     until lReaded = 0;
   finally
     FreeMem( lBuff );
   end;
 finally
   CloseHandle( lFileHandle );
 end;
end;

все бы ничего... да только не всегда получается асинхронный вызов.
в случае попытки чтения большого файла с винчестера функция FileRead ждет окончания чтения и возвращает true (
и только в случае первой попытки обращения к съемному носителю срабатывает часть кода по работе с GetOverlappedResult...
объясните знающие люди, в чем соль?!


 
Riply ©   (2007-12-16 19:49) [1]

После того как FileRead вернет True,
надо вызвать GetLastError, чтобы узнать причину удачи :)


 
MetalFan ©   (2007-12-16 19:57) [2]


> Riply ©   (16.12.07 19:49) [1]

:-P


 
DiamondShark ©   (2007-12-17 14:02) [3]


> else
>               RaiseLastOSError;

Это после вызова GetLastError?


> lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем

а это зачем?! 8-(

А чего б тебе не юзать синхронные вызовы в отдельном потоке?
Код намного менее макаронистый получится.


 
Игорь Шевченко ©   (2007-12-17 14:03) [4]

а вот пример в http://www.delphimaster.ru/articles/named_pipes/index.html
пользует асинхронный воод-вывод аккурат на API и вроде как работает...


 
DiamondShark ©   (2007-12-17 14:19) [5]


> в случае попытки чтения большого файла с винчестера функция
> FileRead ждет окончания чтения и возвращает true

Большой там файл, или не большой -- до лампочки, ты всё равно C_BLOCK_SIZE байт за раз читаешь.

Если эта константа имеет весьма скромное значение, то вполне рациональна стратегия системы считать эти байты с быстрого устройства, не заморачиваясь на сомнительной выгоды асинхронность.


 
tesseract ©   (2007-12-17 14:22) [6]


> не заморачиваясь на сомнительной выгоды асинхронность.


Загрузка процессора программой ниже.


 
MetalFan ©   (2007-12-17 15:04) [7]


> > lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
>
> а это зачем?! 8-(

как зачем? при асинхронном обращении необходимо указать, с какого места чтение осуществляется.
MSDN
Offset
File position at which to start the transfer. The file position is a byte offset from the start of the file. The calling process must set this member before calling the ReadFile or WriteFile function.
This member is used only when the device is a file. Otherwise, this member must be zero.



> А чего б тебе не юзать синхронные вызовы в отдельном потоке?
>
> Код намного менее макаронистый получится.

для этого надо городить отдельный поток. а если у меня будет 500 файлов читаться?

> Большой там файл, или не большой -- до лампочки, ты всё
> равно C_BLOCK_SIZE байт за раз читаешь.

C_BLOCK_SIZE = 50 * 1024 * 1024;
забыл указать.


> Игорь Шевченко ©   (17.12.07 14:03) [4]

нет, тут работа с файловой системой, а не с трубками.

в общем после ряда экспериментов выяснилось:
1. ReadFile возвр.True после небольшой задержки в случае обращения к файлу на винте.
2. ReadFile сразу же возвр.False в случае обращения к файлу на сменном носителе или в сети.

читать пытаюсь файлы >200Mb с буфером >10Mb.


 
DiamondShark ©   (2007-12-17 15:35) [8]


> для этого надо городить отдельный поток.

По сравнению с этим огородом, горожение отдельного потока -- тьфу и растереть.


> а если у меня будет 500 файлов читаться?

То тебе по-любому боглах будет.
Во-первых, 500 буферов по 50 Мб нигде не поместятся.
Во-вторых, код диспетчеризации нескольких асинхронных файлов будет сложнее, чем код простого потока синхронного в/в.
А в-третьих, 500 файлов у тебя всё равно никогда не будет, это ты для красного словца сказал. Если они >200Mb, то в память они всё равно не поместятся, так что обрабатывать их придётся всё равно друг за другом.


> 1. ReadFile возвр.True после небольшой задержки в случае
> обращения к файлу на винте.
> 2. ReadFile сразу же возвр.False в случае обращения к файлу
> на сменном носителе или в сети.

И правильно делает.
Считать с ЖД в память 50 Мб -- дело долей секунды.


 
tesseract ©   (2007-12-17 15:55) [9]


> для этого надо городить отдельный поток. а если у меня будет
> 500 файлов читаться?


Одновременно ? Разница при любом подходе будет малозначительной, винда повиснет наглухо :-)


 
MetalFan ©   (2007-12-17 15:56) [10]


> И правильно делает.
> Считать с ЖД в память 50 Мб -- дело долей секунды.

тоже верно...
видимо основную задержку при вызове ReadFile создает копирование памяти...


 
Alex Konshin ©   (2007-12-26 00:33) [11]

А зачем вообще читать десятки мегабайт в память?
Нужно просто мапить этот файл на память и всё. Никаких проблем.
Работу с файлом оформить в отдельный поток.


 
J_f_S   (2007-12-26 10:30) [12]


> Нужно просто мапить этот файл на память и всё. Никаких проблем.
>
> Работу с файлом оформить в отдельный поток.

+1


 
MetalFan ©   (2007-12-26 19:37) [13]

собстно это было мое исследование(попытки) работы с overlapped.
всем спасибо за участие!


 
Eraser ©   (2007-12-26 21:18) [14]

учитывая рост количества ядер в процах, имеет смысл ориентироваться на синхронную архитектуру, а не наоборот.


 
MetalFan ©   (2007-12-26 23:24) [15]

а почему?


 
Eraser ©   (2007-12-26 23:59) [16]

потому что при увеличении числа ядер/процессоров уменьшаются накладные расходы на переключение контекстов потоков, не говоря уже об общем повышении производительности.


 
MetalFan ©   (2007-12-27 09:00) [17]

а разве утверждение, что "оптимальное кол-во потоков равно числу ядер/процессоров" неверно?


 
Alex Konshin ©   (2007-12-27 10:38) [18]

Неверно в корне.
Во-первых, есть ещё такая штука как гипертрединг (который обещают вернуть в следующих поколениях многоядерников).
Во-вторых, есть и другие (и системные в том числе) процессы со своими потоками.
В-третьих, ваши потоки когда-нибудь будут ждать.
...
А есть ещё и в-пятых, и в-двадцатых...


 
Alex Konshin ©   (2007-12-27 10:48) [19]

> Eraser ©   (26.12.07 21:18) [14]
> учитывая рост количества ядер в процах, имеет смысл ориентироваться
> на синхронную архитектуру, а не наоборот.

Не вижу логики. Что ты называешь синхронной архитектурой?
Наоборот, сейчас имеет смысл распараллеливать всё что можно, то есть всё делать асинхронно. И чем дальше, тем это становится более актуально. Например, в ближайшие пару лет появятся 8-ми ядерные процессоры, а на них может быть гипертрединг, тогда чем сильнее распараллелишь, тем быстрее будет работать (там где это имеет смысл, естественно). Кстати, Delphi в этом плохой помошник, точнее вообще никакой, и никаких намёков на улучшение ситуации.


 
Eraser ©   (2007-12-27 12:27) [20]


> Alex Konshin ©   (27.12.07 10:48) [19]


> Что ты называешь синхронной архитектурой?

В данном случае я имею ввиду архитекуру, при которой для каждого соединения создается отдельный поток.
асинхронная арихеткура как раз подразумевает то, что достаточно всего одного потока для работы со множеством соединений, в ряде случаев это дейтсивительно дает приемущество, но учитывая [14] подход будет меняться, тем более что с т.з. программиста организоваться синхронную передачу данных куда проще. Насчет распараллеливания полностью согласен, через несколько лет появятся встроенные языковые средства для поддержки многопоточности.


 
MetalFan ©   (2007-12-27 17:21) [21]


> через несколько лет появятся встроенные языковые средства
> для поддержки многопоточности

какие такие средства? а TThread - это не средство?


 
Eraser ©   (2007-12-27 17:37) [22]


> MetalFan ©   (27.12.07 17:21) [21]

нет, TThread это не языковое средство поддержки многопоточности..
единственное языковое средство в Делфи, связанное с многопоточностью приходит на ум только ThreadVar.


 
MetalFan ©   (2007-12-27 18:25) [23]


> Eraser ©   (27.12.07 17:37) [22]

понял. спасибо)


 
имя   (2008-05-08 10:43) [24]

Удалено модератором



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2009.05.24;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.006 c
6-1203266485
Lamer666
2008-02-17 19:41
2009.05.24
Отправка писем с локальной машины прямо на почтовые ящики


11-1201052252
Elec3C
2008-01-23 04:37
2009.05.24
Вопрос по IniFile (ValueString)


2-1239259328
worldmen
2009-04-09 10:42
2009.05.24
Ошибки при добавление картинок в БД Interbase


2-1238466628
8shar
2009-03-31 06:30
2009.05.24
ID скрытого процесса


11-1200582121
MTsv DN
2008-01-17 18:02
2009.05.24
Странная вещь...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский