I/O Concept - Blocking/Non-Blocking VS Sync/Async
I/O Concept - Blocking/Non-Blocking VS Sync/Async
These concepts are discussed in the context of WinSock, but the basic ideas can be applied to other I/O types and also on other OS, such as Linux/Unix world as well.
I - Blocking V.S. Non-Blocking
Under blocking mode, socket I/O operations, connect and accept operations all block until the operation in question is completed.
Under non-blocking mode, if a Winsock call cannot complete immediately, the call fails and WSAGetLastError() returns a WSAEWOULDBLOCK error.
The calls always return immediately, but if failed, nothing happened, i.e. no I/O request is issued at all.
When a socket is created, by default it is a blocking socket.To change the socket operation mode from blocking mode to nonblocking mode, you can either use WSAAsyncSelect(), WSAEventSelect(), or the FIONBIO command in the ioctlsocket() API call.
II - Sync V.S. Async
On windows platform, Async I/O is also called Overlapped I/O.
In Winsock 2, you create an overlapped socket using WSASocket() with the WSA_FLAG_OVERLAPPED flag, or simply using the socket() API. You can use the Win32 file I/O APIs or Winsock 2 WSASend(), WSASendTo(), WSARecv(), and WSARecvFrom() to initiate an overlapped I/O operation.
If an overlapped I/O operation can not complete immediately, the call fails and WSAGetLastError() return WSA_IO_PENDING or ERROR_IO_PENDING, which is actually the same define as WSA_IO_PENDING.
So all calls return immediately, but if the operation can't be
completed at that time, corresponding request is issued to the
underlying system.
By setting a socket's overlapped I/O
attribute it doesn't mean that the socket will perform an overlapped
I/O operation. For example, if you specify NULL for both the completion function and the overlapped structure in WSARecv() and WSASend(), or you simply call recv
or send functions, they will complete in a blocking fashion. To make
sure the I/O is performed in an overlapped fashion you need to provide
an overlapped structure in your I/O function, depending on the function
you use.
If you use the SO_RCVBUF and SO_SNDBUF option to set zero TCP stack receive and send buffer, you basically instruct the TCP stack to directly perform I/O using the buffer provided in your I/O call. Therefore, in addition to the non-blocking advantage of the overlapped socket I/O, the other advantage is better performance because you save a buffer copy between the TCP stack buffer and the user buffer for each I/O call.
III - I/O Multiplexing VS Async I/O
1.
In I/O Multiplexing, you want to be notified if one or more I/O
conditions are ready. (So issuing some I/O operation won't be blocked)
2.
In Asyn model, I/O operations won't block even if it can't be completed
immediately. (So that you can issue multiple I/O requests simultaneously). When you get notification message, it tells you that the I/O operations are completed.
As summarized in [2][3]:
- Blocking I/O
means that the calling system does not return control to the caller
until the operation is finished. As a result, the caller is blocked and
cannot perform other activities during that time.
- Non-blocking Synchronous I/O
means that call returns control to the caller immediately and the
caller is not made to wait. The invoked system immediately returns one
of two responses: If the call was executed and the results are ready,
then the caller is told of that. Alternatively, the invoked system can
tell the caller that the system has no resources (no data in the
socket) to perform the requested action.
- Non-blocking Asynchronous I/O
means that the calling function returns control to the caller
immediately, reporting that the requested action was started. The
invoked system will notify the caller (by callback for example), when
the result is ready for processing.
[Reference]
1. https://support.microsoft.com/kb/181611
2. Advanced Programming in Unix Environment
3. Two High Performance I/O Design Patterns
4. Boost application performance using asynchronous I/O