views:

282

answers:

4

When I run this program

OVERLAPPED o;

int main()
{
    ..
    CreateIoCompletionPort(....);

    for (int i = 0; i<10; i++)
    {
        WriteFile(..,&o);

        OVERLAPPED* po;
        GetQueuedCompletionStatus(..,&po);
    }
}

it seems that the WriteFile didn't return until the writing job is done. At the same time , GetQueuedCompletionStatus() gets called. The behavior is like a synchronous IO operation rather than an asynch-IO operation.

Why is that?

A: 

If GetQueuedCompletionStatus is being called, then the call to WriteFile is synchronous (and it has returned), but it can still modify &o even after it's returned if it is asynchronous.

Orion Adrian
Is it documented by Microsoft? Where can I find a convinced answer?
Jinx
Code in a code block cannot execute until the first code block has returned, but any method/function can launch another thread to do a task. It's on that thread that it can manipulate the data after the fact, but the statements following a function call will not execute until the function call returns.
Orion Adrian
When I delete the GetQueuedCompletionStatus() in my program, it still behaves synchronously.
Jinx
A: 

from this page in MSDN:

For asynchronous write operations, hFile can be any handle opened with the CreateFile function using the FILE_FLAG_OVERLAPPED flag or a socket handle returned by the socket or accept function.

also, from this page:

If a handle is provided, it has to have been opened for overlapped I/O completion. For example, you must specify the FILE_FLAG_OVERLAPPED flag when using the CreateFile function to obtain the handle.

shoosh
I have these stuff in my program ,but the program still behaves like sync-io.
Jinx
so maybe instead of letting us guess you should provide the full details of your code.
shoosh
+1  A: 

If the file handle and volume have write caching enabled, the file operation may complete with just a memory copy to cache, to be flushed lazily later. Since there is no actual IO taking place, there's no reason to do async IO in that case.

Internally, each IO operation is represented by an IRP (IO request packet). It is created by the kernel and given to the filesystem to handle the request, where it passes down through layered drivers until the request becomes an actual disk controller command. That driver will make the request, mark the IRP as pending and return control of the thread. If the handle was opened for overlapped IO, the kernel gives control back to your program immediately. Otherwise, the kernel will wait for the IRP to complete before returning.

Not all IO operations make it all the way to the disk, however. The filesystem may determine that the write should be cached, and not written until later. There is even a special path for operations that can be satisfied entirely using the cache, called fast IO. Even if you make an asynchronous request, fast IO is always synchronous because it's just copying data into and out of cache.

Process monitor, in advanced output mode, displays the different modes and will show blank in the status field while an IRP is pending.

There is a limit to how much data is allowed to be outstanding in the write cache. Once it fills up, the write operations will not complete immediately. Try writing a lot of data at once, with may operations.

Chris Smith
+1  A: 

I wrote a blog posting a while back entitled "When are asynchronous file writes not asynchronous" and the answer was, unfortunately, "most of the time". See the posting here: http://www.lenholgate.com/archives/000765.html.

The gist of it is:

  • For security reasons Windows extends files in a synchronous manner
  • You can attempt to work around this by setting the end of the file to a large value before you start and then trimming the file to the correct size when you finish.
  • You can tell the cache manager to use your buffers and not its, by using FILE_FLAG_NO_BUFFERING
  • At least it's not as bad as if you're forced to use FILE_FLAG_WRITE_THROUGH
Len Holgate