ReadFile не работает асинхронно на Win7 и Win2k8 - PullRequest
4 голосов
/ 02 февраля 2011

Согласно MSDN, ReadFile может считывать данные 2 разными способами: синхронно и асинхронно. Мне нужен второй. Следующий код демонстрирует использование с OVERLAPPED struct:

#include <windows.h>
#include <stdio.h>
#include <time.h>

void Read()
{
    HANDLE hFile = CreateFileA("c:\\1.avi", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        printf("Failed to open the file\n");
        return;
    }

    int dataSize = 256 * 1024 * 1024;
    char* data = (char*)malloc(dataSize);
    memset(data, 0xFF, dataSize);

    OVERLAPPED overlapped;
    memset(&overlapped, 0, sizeof(overlapped));

    printf("reading: %d\n", time(NULL));
    BOOL result = ReadFile(hFile, data, dataSize, NULL, &overlapped);
    printf("sent: %d\n", time(NULL));


    DWORD bytesRead;
    result = GetOverlappedResult(hFile, &overlapped, &bytesRead, TRUE); // wait until completion - returns immediately
    printf("done: %d\n", time(NULL));

    CloseHandle(hFile);
}



int main()
{
        Read();
}

В Windows XP вывод: чтение: 1296651896 отправлено: 1296651896 сделано: 1296651899

Это означает, что ReadFile не блокировался и немедленно возвращался в ту же секунду, тогда как процесс чтения продолжался в течение 3 секунд. Это нормальное асинхронное чтение.

Но на Windows 7 и Windows 2008 я получаю следующие результаты: чтение: 1296661205 отправлено: 1296661209 сделано: 1296661209. Это поведение синхронного чтения.

MSDN говорит, что async ReadFile иногда может вести себя как синхронизация (например, когда файл сжат или зашифрован). Но возвращаемое значение в этой ситуации должно быть ИСТИНА и GetLastError() == NO_ERROR. В Windows 7 я получаю FALSE и GetLastError() == ERROR_IO_PENDING. Поэтому WinApi говорит мне, что это асинхронный вызов, но когда я смотрю на тест, я вижу, что это не так!

Я не единственный, кто нашел эту "ошибку": прочитайте комментарий на странице ReadFile MSDN.

Так в чем же решение? Кто-нибудь знает? Прошло 14 месяцев после того, как Денис обнаружил это странное поведение.

Ответы [ 5 ]

4 голосов
/ 10 февраля 2011

Я не знаю размер файла "c: \ 1.avi", но размер буфера, который вы даете Windows (256M!), Вероятно, достаточно велик для хранения файла.Поэтому Windows решает прочитать весь файл и поместить его в буфер так, как ему нравится.Вы не говорите Windows «Я хочу асинхронность», вы говорите «Я знаю, как обрабатывать асинхронность».

Просто измените размер буфера, скажем, 1024, и ваша программа будет вести себя точно так же, но только для чтения1024 байта (и также возвращают ERROR_IO_PENDING).

В общем, вы делаете асинхронный, потому что вы хотите сделать что-то еще во время операции.Посмотрите на пример здесь: Тестирование конца файла , поскольку он демонстрирует асинхронный файл ReadFile.Если вы измените буфер сэмпла и установите для него большое значение, он должен вести себя точно так же, как ваш.

PS: я предлагаю вам не полагаться на временные сэмплы для проверки, использования кодов возврата и событий

1 голос
/ 13 февраля 2011

Windows7 / Server2008 имеют другое поведение для разрешения условия гонки, которое может возникнуть в GetOverlappedResultEx.Когда вы компилируете для этих ОС, Windows обнаруживает это и использует другое поведение.Я нахожу это злым заблуждением.

Вот ссылка: http://msdn.microsoft.com/en-us/library/dd371711(VS.85).aspx

Я уверен, что вы читали это много раз в прошлом, но часть текста изменилась с Win7- esp поле hEvent в структуре OVERLAPPED, http://msdn.microsoft.com/en-us/library/ms684342(v=VS.85).aspx

Такие функции, как GetOverlappedResult и функции ожидания синхронизации, сбрасывают события автоматического сброса в состояние без сигнала. Следовательно, вы должны использовать событие ручного сброса ; если вы используете событие автоматического сброса, ваше приложение может перестать отвечать, если вы дождетесь завершения операции , а затем вызовите GetOverlappedResult с параметром bWait, установленным в значение ИСТИНА.

можетВы делаете эксперимент - пожалуйста, выделите событие ручного сброса в вашей структуре OVERLAPPED вместо события автоматического сброса?(Я не вижу распределения в вашем фрагменте кода - не забудьте создать событие и установить 'hEvent' после обнуления структуры)

1 голос
/ 11 февраля 2011

Вы пытались использовать событие, как предложил @Simon Mourier? Я знаю, что в документации сказано, что событие не требуется, но если вы видите пример в ссылках, предоставленных @Simon Mourier, оно использует событие для асинхронного чтения.

1 голос
/ 03 февраля 2011

Согласно this , я подозреваю, что в вашем случае он должен вернуть TRUE. Но может также случиться так, что стандартные настройки режимов завершения отличаются на Win7 / Win2k8. Попробуйте установить другой режим с помощью SetFileCompletionNotificationModes ().

1 голос
/ 02 февраля 2011

Возможно, это как-то связано с кэшированием.Попробуйте открыть файл без кэширования (FILE_FLAG_NO_BUFFERING)

РЕДАКТИРОВАТЬ

Это фактически задокументировано в документации MSDN для ReadFile :

Примечание. Если файл или устройство открыты для асинхронного ввода-вывода, последующие вызовы функций, таких как ReadFile, использующих этот дескриптор, обычно возвращаются немедленно, но также могут вести себя синхронно в отношении заблокированного выполнения.Для получения дополнительной информации см http://support.microsoft.com/kb/156932.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...