Real IO operations involve interaction with IO devices, and the operating system restricts applications from directly interacting with devices. The IO operation we usually talk about is actually the interaction between the application program and the operating system. Generally, the System Call of the operating system is used, that is, the system call. Reading is read(), and writing is write(). Different operating systems may implement difference, but the functionality is the same. By calling read, the data is copied from the operating system kernel buffer to the application program buffer; calling write is to copy the data from the application program buffer to the operating system kernel buffer. To really interact with IO devices, the operating system initiates a system interrupt at an appropriate time, finds the interrupt vector and interacts with the corresponding device.
Therefore, IO is divided into two stages, one is the kernel and device interaction stage, and the other is the kernel and application interaction stage.
Synchronous IO and asynchronous IO
Synchronous IO
means that the user thread is the party that initiates the IO request actively, and the operating system kernel is the party that passively accepts the IO request.
Asynchronous IO
is the opposite of synchronous IO, which means that the operating system kernel is the party that initiates the IO request actively, and the user thread is the party that passively accepts it. The user thread registers the callback functions of various IO events with the kernel, and the kernel actively calls them.
Blocking IO and non-blocking IO
Blocking IO
means that the kernel IO operation needs to be completely completed before returning to the user thread to continue execution. Blocking refers to the execution state of the user program.
Non-blocking IO
means that the user program does not need to wait for the kernel IO operation to be completely completed. After calling the IO, the kernel will immediately return a status value to the user thread. The user thread can continue to execute, and the thread is in a non-blocking state.
BIO
BIO is blocking IO, synchronous blocking IO. The application starts from the IO system call until the system call returns. During this time, the user thread is blocked. After returning successfully, the thread starts processing the application buffer data.
Assuming that the BIO model is used to read a file on the disk:
(1) From the read system call, the user thread enters the blocked state.
(2) When the system kernel receives the read system call, it begins to prepare data. At the beginning, the data may not have reached the kernel buffer (a block may not have been read), and the kernel needs to wait.
(3) The kernel waits until the complete data arrives, copies the data from the kernel buffer to the application buffer, after which read returns the result (returns the number of bytes copied into the user buffer).
(4) After read returns, the user thread will recover from blocking and continue to run.
Therefore, the BIO model is in the two stages of the IO operation of the kernel, and the user thread is blocked.
For example, Xiao Wang went to a restaurant to eat and ordered a Ma La Tang, and then he kept staring at the food outlet until the boss placed a Ma La Tang at the food outlet. After that, he went to fetch Malatang and ate it.
Among them, Xiao Wang is the application program, and the boss is the operating system kernel. The action of ordering food is to initiate an IO request, and the action of getting food is to copy from the kernel buffer to the process buffer.
Since it is Xiao Wang who initiates ordering, this is synchronous; but Xiao Wang has been staring at the food pick-up port without doing anything else, indicating that he is in a blocked state, so this is a synchronous blocking IO model.
NIO
Non-Blocking IO, non-blocking IO. In the NIO model, once the application thread starts the IO system call, the following two situations will occur:
(1) If there is no data in the kernel buffer, the system call will return immediately and return a call failure message.
(2) If there is data in the kernel buffer, it is blocked until the data is copied from the kernel buffer to the user process buffer, the system call returns successfully, and the thread resumes running.
Assuming that the NIO model is used to read a file on the disk:
(1) When the kernel data is not ready, when the user thread initiates an IO request, it returns immediately. Generally, in order to read the final data, the user thread needs to continuously initiate IO system calls (while loop).
(2) After the kernel data arrives, when the user thread initiates a system call, the user thread enters the blocking state. The kernel starts copying data, copies the data from the kernel buffer to the process buffer, and the kernel returns the result.
(3) After the user thread reads the data, it unblocks the state and continues to run. That is to say, the user process needs to go through several attempts to ensure that the data is actually read in the end, and then continue to execute.
Therefore, in the NIO model, during the interaction between the operating system and the device, the user thread is in a non-blocking state. During the interaction between the operating system and the application, the user thread needs to block to copy the buffer.
It was still Xiao Wang who went to the restaurant to eat and ordered a Malatang. Before eating, he asked the boss if the meal was ready, and the boss replied no, and then he asked every 3 minutes until the meal was ready. After that, he went to fetch Malatang and ate it.
Since it was still Xiao Wang who initiated the order, this is synchronous; ask the boss and the boss will reply immediately, indicating that it is non-blocking, so this is a synchronous non-blocking IO model.