ReadFile doesn't work asynchronously on Win7 and Win2k8

做~自己de王妃 提交于 2019-12-06 06:13:48

问题


According to MSDN, ReadFile can read data 2 different ways: synchronously and asynchronously. I need the second one. The folowing code demonstrates usage with 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();
}

On Windows XP output is: reading: 1296651896 sent: 1296651896 done: 1296651899

It means that ReadFile didn't block and returned imediatly at the same second, whereas reading process continued for 3 seconds. It is normal async reading.

But on windows 7 and windows 2008 I get following results: reading: 1296661205 sent: 1296661209 done: 1296661209. It is a behavior of sync reading.

MSDN says that async ReadFile sometimes can behave as sync (when the file is compressed or encrypted for example). But the return value in this situation should be TRUE and GetLastError() == NO_ERROR. On Windows 7 I get FALSE and GetLastError() == ERROR_IO_PENDING. So WinApi tells me that it is an async call, but when I look at the test I see that it is not!

I'm not the only one who found this "bug": read the comment on ReadFile MSDN page.

So what's the solution? Does anybody know? It is been 14 months after Denis found this strange behavior.


回答1:


I don't know the size of the "c:\1.avi" file but the size of the buffer you give to Windows (256M!) is probably big enough to hold the file. So windows decides to read the whole file and put it in the buffer the way it likes. You don't say to windows "I want async", you say "I know how to handle async".

Just change the buffer size say 1024, and your program will behave exactly the same, but read only 1024 bytes (and return ERROR_IO_PENDING as well).

In general, you do asynchronous because you want to do something else during the operation. Look at the sample here: Testing for the End of a File, as it demonstrate an async ReadFile. If you change the sample's buffer and set it to a big value, it should behave exactly like yours.

PS: I suggest you don't rely on time samples to check things, use return codes and events




回答2:


According to this, I would suspect that it should return TRUE in your case. But it may also be that the completion modes default settings are different on Win7/Win2k8. Try setting a different mode with SetFileCompletionNotificationModes().




回答3:


Have you tried to use an event as @Simon Mourier suggested ?. I know that the documentation says that the event is not required, but if you see the example in links provided by @Simon Mourier, it is using an event for asynchronous read.




回答4:


Windows7/Server2008 have different behavior to resolve a race condition that can occurn in GetOverlappedResultEx. When you compile for these OS's Windows detects this and uses different behavior. I find this wicked confusing.

Here is a link: http://msdn.microsoft.com/en-us/library/dd371711(VS.85).aspx

I'm sure you've read this many times in the past, but some of the text has changed since Win7 - esp the hEvent field in the OVERLAPPED struct, http://msdn.microsoft.com/en-us/library/ms684342(v=VS.85).aspx

Functions such as GetOverlappedResult and the synchronization wait functions reset auto-reset events to the nonsignaled state. Therefore, you should use a manual reset event; if you use an auto-reset event, your application can stop responding if you wait for the operation to complete and then call GetOverlappedResult with the bWait parameter set to TRUE.

could you do an experiment - please allocate a manual reset event in your OVERLAPPED struct instead of a auto reset event? (I dont see the allocation in your snippit - dont forget to create the event and to set 'hEvent' after zeroing the struct)




回答5:


This probably has something to do with caching. Try to open the file non-cached (FILE_FLAG_NO_BUFFERING)

EDIT

This is actually documented in the MSDN documentation for ReadFile:

Note If a file or device is opened for asynchronous I/O, subsequent calls to functions such as ReadFile using that handle generally return immediately, but can also behave synchronously with respect to blocked execution. For more information see http://support.microsoft.com/kb/156932.



来源:https://stackoverflow.com/questions/4878868/readfile-doesnt-work-asynchronously-on-win7-and-win2k8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!