непонятная задержка при выполнении CloseHandle

Тема в разделе "WASM.BEGINNERS", создана пользователем Xerx, 7 май 2007.

  1. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Вот есть кусок кода ()
    Код (Text):
    1.     ; создаю новый файл...
    2.     ; ...
    3.     ; выделяю место под него (допустим 1Гб)
    4.     invoke  SetFilePointer, hFile, 1024*1024*1024, NULL, FILE_BEGIN
    5.     invoke  SetEndOfFile, hFile
    6.     ; закрываю файл
    7.     invoke  CloseHandle, hFile
    Так вот. После вызова SetEndOfFile файл получает нужный размер мгновенно, а вот при закрытии через CloseHandle начинается (насколько понимаю) реальное выделение места под него на винчестере. Для больших файлов (скажем в 4Гб) у меня это может занимать до минуты и более. В это время приложение "висит", т.к выделение происходит в главном потоке. Тут все понятно.

    Далее, чтобы избежать такого зависания, делаю тоже самое в цикле, таким образом:
    Код (Text):
    1.     .while (ebx > 0)
    2.         invoke  SetFilePointer, hFile, 1024*1024, NULL, FILE_CURRENT
    3.         invoke  SetEndOfFile, hFile
    4.         invoke  FlushFileBuffers, hFile ; даже так делаю
    5.         dec     ebx
    6.         ; тут обрабатываю сообщения, поступившие окну
    7.         ; ...
    8.     .endw
    В процессе работы происходит нормальное выделение места под файл (размер постепенно растет).
    Но, когда я вызываю CloseHandle(), опять все виснет (примерно на то же самое время). Судя по всему данная переделка вообще никак не сказалась на результате.

    Так вот вопрос: как можно выделить места под файл ИНТЕРАКТИВНО(с обработкой сообщений для окна), без использования WriteFile для поблочной записи (очень меделенно получается), и БЕЗ паузы при вызове CloseHandle?

    P.S. Есть идея использовать для этого FileMapping, но это только идея, не проверял.

    Кто что может сказать по этому поводу?
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Xerx
    Ну а что тут удивительного, создаёшь такой большой файл, и CloseHandle его сбрасывает на диск. Можно использовать асинхронные методы работы с файлом.
     
  3. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Xerx
    Попробуй SetFileValidData
     
  4. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    green
    Взял с msdn.microsoft.com:
    И что это за логический конец?

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

    И наконец, у меня НЕТ описания этой функции для masm. Где бы его добыть, если конечно поможет?

    В общем, ничего не понял и прошу объяснить...
     
  5. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    попробуй в цикле переоткрывать файл. типа клоузхендл а потом снова криэйтфайл
     
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.347
    закрывай его в отдельном потоке :)
     
  7. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    FileMapping идея хорошая!
     
  8. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Great Пробовал. По скорости уж лучше писать поблочно... :dntknw:

    rmn Не подходит. Я же писал, что нужна ИНТЕРАКТИВНОСТЬ (нужно видеть, сколько уже выделено: % или Мб)

    asmfan Похоже и в заправду ничего лучше нет...

    green Так все же, можно поподробнее?
     
  9. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Xerx
    Причина тормозов, очевидно, в том, что при увеличении размера файла через SetEndOfFile выделяемая под него область на диске инициализируется нулями (главным образом, из соображений безопасности). SetFileValidData позволяет принудительно объявить эту область, как валидную, т.е. уже содержащую данные этого файла и тем самым избежать инициализации.
    В этом случае файл будет содержать "случайные" данные - остатки когда-то удалённых файлов.
    Кстати, именно поэтому SetFileValidData требует доп. привилегий.

    Прототип на С & MASM:
    Код (Text):
    1. BOOL SetFileValidData(
    2.   HANDLE hFile,
    3.   LONGLONG ValidDataLength
    4. );
    5.  
    6. PROTO SetFileValidData hFile:HANDLE, ValidDataLength:QWORD
    --
    Т.е. в твоем примере надо так:
    Код (Text):
    1.     ; создаю новый файл...
    2.     ; ...
    3.     ; выделяю место под него (допустим 1Гб)
    4.     invoke  SetFilePointer, hFile, 1024*1024*1024, NULL, FILE_BEGIN
    5.     invoke  SetEndOfFile, hFile
    6.     invoke  SetFileValidData, hFile, 1024*1024*1024
    7.     ; закрываю файл
    8.     invoke  CloseHandle, hFile
     
  10. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    green
    Нет, не инициализируется она ничем. Поверял.

    Попробовал SetFileValidData(), но выдает ERROR_INVALID_PARAMETER.
    Прочитал в MSDN:
    И не понял как соотнести ТЕКУЩИЙ ПРАВИЛЬНЫЙ РАЗМЕР, ТЕКУЩИЙ РАЗМЕР ФАЙЛА и НУЖНЕЙ МНЕ РАЗМЕР...
    Плюс еще говорится о привилегии SE_MANAGE_VOLUME_NAME. Мне нужно ее получать или как?
     
  11. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Xerx
    То есть? Ты хочешь сказать, что после выполнения твоего куска из #1 файл на диске не заполнен нулями?
    Ты делал, как в примере #9?
    Надо.
     
  12. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    green
    Да, вот так:
    Код (Text):
    1. invoke  SetFilePointer, hFile, 1024*1024, NULL, FILE_BEGIN
    2. invoke  SetEndOfFile, hFile
    3. push    1024*1024
    4. push    hFile
    5. call    SetFileValidData
    6. ; выдает ERROR_INVALID_PARAMETER
    Нашел такой пример:
    Код (Text):
    1. #define STEALCLUSTERS 10
    2. #include <windows.h>
    3. #include <stdio.h>
    4. int main(int argc, char * argv[]) {
    5. char * sNULL = 0;
    6. DWORD dwSectorsPerCluster = 0, dwBytesPerSector = 0,
    7. dwNumberOfFreeClusters = 0, dwTotalNumberOfClusters = 0,
    8. dwWritten = 0;
    9. GetDiskFreeSpace(sNULL,&dwSectorsPerCluster,
    10. &dwBytesPerSector,&dwNumberOfFreeClusters,&dwTotalNumberOfClusters);
    11. HANDLE hToken, h;
    12. TOKEN_PRIVILEGES tp;
    13. LUID luid;
    14. OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken);
    15. if(!LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &luid)) {
    16. printf("LookupPriv err: %u\n",GetLastError()); }
    17. else {
    18. tp.PrivilegeCount = 1;
    19. tp.Privileges[0].Luid = luid;
    20. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    21. if(!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
    22. (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)) {
    23. printf("AdjustToken err: %u\n", GetLastError()); }
    24. else {
    25. h = CreateFile("datatheft.dat",GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,0,0);
    26. if(h) {
    27. if(SetFilePointer(h,dwBytesPerSector * dwSectorsPerCluster *
    28. STEALCLUSTERS,0,FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
    29. printf("SetFilePointer failed: %u\n",GetLastError()); }
    30. SetEndOfFile(h);
    31. // steal data from slack by setting new logical end of file to length of file slack
    32. // (bytes per cluster * STEALCLUSTERS) minus 1 (to avoid exceeding physical eof)
    33. if(!SetFileValidData(h,dwBytesPerSector * dwSectorsPerCluster * STEALCLUSTERS - 1)) {
    34. printf("Error calling SetFileValidData: %u\n",GetLastError()); }
    35. else {
    36. printf("File slack space sector data theft successful.\n"); }}}
    37. CloseHandle(h);
    38. CloseHandle(hToken); }
    39. return 0;
    40. }
    Извиняюсь за оформление, но это певоисточник.
    Так вот, стоит с этим возиться? Вроде то, что мне нужно. (Просто никогда раньше не сталкивался с получением прав :dntknw: )
     
  13. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Xerx
    Код (Text):
    1. push    1024*1024
    2. push    hFile
    3. call    SetFileValidData
    4. ; выдает ERROR_INVALID_PARAMETER
    И не удивительно, что выдаёт ошибку.
    Посмотри ещё раз на прототип SetFileValidData - второй параметр QWORD, а не DWORD!
    т.е. надо
    Код (Text):
    1. push 0
    2. push    1024*1024
    3. push    hFile
    4. call    SetFileValidData
     
  14. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    green
    Это ж надо было так лопухнуться! :-(
     
  15. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Я думаю админ не будет против удалить предыдущий пост :derisive: Как-то он по-другой теме :-(
    Да и этот пост заодно....
     
  16. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    Снова вернусь к данной теме. С тех пор я пришел к такому выводу:
    1) размер при вызове SetFileValidData должен быть на 1 меньше того, что был задан SetFilePointer
    2) эта функция работает ТОЛЬКО на NTFS.

    С первым - без проблем! А по второму у меня очевидный вопрос: а что делать с FAT32???

    И что, неужели никто не может ответить?
     
  17. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    И еще. Вариант с file-mapping'ом не прошел. При попытке позиционирования вне файла возникает естественная ошибка доступа к чужой памяти... ее можно как-то обойти? (флаги какие при создании)
     
  18. OFFSIDE

    OFFSIDE New Member

    Публикаций:
    0
    Регистрация:
    23 сен 2006
    Сообщения:
    106
    У меня прошел вариант с _lclose. A CloseHandle после него.

    Добавлено

    Но к сожалению только на флеш накопителе. На жестком диске та же задержка. Судя по всему, происходит выделение места под файл, и идет запись в MFT. Проверить бы на дефрагментированном жеском диске это предположение!
     
  19. Xerx

    Xerx Алексей

    Публикаций:
    0
    Регистрация:
    17 фев 2005
    Сообщения:
    528
    Адрес:
    Russia
    OFFSIDE
    Проверял. Задержка меньше, но все равно приличная. Даже не знаю, что еще можно придумать...
     
  20. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Xerx
    Странно, что SetFileValidData не работает с FAT...
    А без SetFileValidData на фате сильные тормоза?