Asynchronous I/O
File and socket operations in ConcurrentTasks are overlapped Windows I/O on the core's I/O completion port. A task starts an operation and is suspended; when the operation completes, the core's I/O thread resumes it. No thread blocks in between.
Enabling asynchronous I/O
AsyncIo::EnableAsyncIo creates the completion port and the I/O thread that drains it; AsyncIo::DisableAsyncIo takes it back. The calls are counted, so a library and the application can both enable it.
Important
Enable asynchronous I/O before you create files or sockets, and disable it only when no operation is pending any more.
How an operation runs
- A file or socket is opened for overlapped I/O and associated with the port
(AssociateHandleWithIoCompletionPort).
AsyncFile and AsyncSocket do this in their
Create. - Each operation carries a request object that owns the
OVERLAPPED(AsyncIoRequestBase). The Win32 call is started with it. - When the operation completes, the I/O thread passes the result to the request (RequestCompleted). A waitable request sets an event, which resumes the waiting task.
- If the operation completes at once, the request is completed on the calling thread and no completion packet follows.
Waiting and starting forms
The library offers each operation in two forms:
- Waiting — AsyncFile::Read, AsyncSocket::Recv and so on start the operation and suspend the calling task until it completes, optionally with a timeout. They need a task or a converted thread.
- Starting — AsyncFile::ReadAsync, AsyncSocket::RecvAsync and so on only start the operation and return. You wait later on the request (for example a WaitableAsyncFileIoRequest), which lets one task keep several operations in flight.
On top of that, AsyncFile::ReadFile and WriteFile move a whole file through a sequential memory with several requests in flight, and StreamedFileReader and OrderedFileWriter stream large files with bounded memory.
Important
A request and its buffer must stay alive and in place until the operation has completed. Close or destroy a file or socket only when no operation on it is pending.
Errors
File operations return Win32 error codes (ErrorCode; ERROR_SUCCESS on
success), socket operations Winsock codes (WinsockErrorCode). The starting
forms may also return the "pending" code of their API.