Five I/O models of Linux

There are five I/O models under Linux: blocking I/O, non-blocking I/O, I/O multiplexing, signal-driven I/O, and asynchronous I/O. Among them, the first four are called synchronous I/O. Before understanding these five kinds of I/O, you need to clarify several concepts such as synchronous/asynchronous, blocking/non-blocking.

1. The concepts of synchronous, asynchronous, blocking, and non-blocking

synchronous and asynchronous

Synchronous and asynchronous focus on the message communication mechanism.
The so-called synchronization means that when a function call is issued, the call will not return until the result is obtained. Once it returns, it is the return value. For example, when calling the readfrom system call, it must wait until the IO operation is completed before returning, which is a synchronous call.

The so-called asynchronous means that after the call is issued, the call returns directly. In other words, when an asynchronous call occurs, the caller will not get the result immediately. Instead, after the call is issued and the conditions are met, the callee notifies the caller to process the result through a signal or callback. For example: when calling the aio_read system call, it returns directly without waiting for the IO operation to complete, and the call result is notified to the caller through a signal.

To give a popular example:
You call the bookstore owner and ask if he has the book "Advanced Programming in UNIX Environment". If it is a synchronous communication mechanism, the boss will say, wait a moment, "I'll check it out", and then he will start to check it. Check, wait for the check (it may be 5 seconds, or it may be a day) and tell you the result (return result).
As for the asynchronous communication mechanism, the bookstore owner directly tells you that I will check it, and after checking it, I will call you to tell you, and then hang up the phone directly (without returning the result). Then check it out, and he will take the initiative to call you. Here the boss calls back by "calling back".

blocking and non-blocking

Blocking and non-blocking focus on the status of the program while waiting for the call result (message, return value).
A blocking call means that the current thread will be suspended before the result of the call is returned. The calling thread will not return until it has the result.
A non-blocking call means that the call will not block the current thread until the result cannot be obtained immediately.

Still the above example:
you call the bookstore owner to ask if there is a book "Advanced Programming in UNIX Environment". If you make a blocking call, you will keep "hanging" yourself until you get the result of whether the book here is available. ; If it is a non-blocking call, you don't care if the boss tells you or not, you go to play first, of course, you have to occasionally check in a few minutes to see if the boss has returned the result.
Here blocking and non-blocking have nothing to do with whether it is synchronous or asynchronous. It has nothing to do with how the boss answers your results.

Two, the five classic I/O models under Linux

blocking I/O

When a Linux user process reads data, it needs to go through two stages:
(1) Waiting for the data to be ready
(2) Reading data
If the user process tries to read data, but the data has not yet reached the kernel space, or has reached the kernel buffer, But it has not been copied to the user space. At this time, the user process cannot read the data and will enter blocking.

non-blocking I/O

In non-blocking I/O, if the process does not get the data, the process will immediately return the result instead of blocking in place.
There will be two stages involved here:
Stage 1:
The user process tries to read the data, but the data has not yet arrived (not ready). At this time, the kernel is in a waiting state; but because it is non-blocking IO, the user will return an exception at this time, that is, the user process It will not block and wait; ① After the user process gets the error, try to read again, ① go round and round until the data is ready.
The whole process is very similar to CPU polling.
Stage 2:
At this time, the data has arrived and has come to the kernel buffer, which means it is ready; but the data is only in the kernel space and has not been copied to the user space, so the user process still cannot process the data at this time and continues to block.
Until the data is copied to the user space, the user process is unblocked and begins to process the data.

I/O multiplexing

I/O multiplexing is often used in socket programming. It uses a single thread to monitor multiple FDs at the same time, and is notified when a certain FD is readable or writable, avoiding invalid waiting and making full use of CPU resources. Commonly used IO multiplexing has the following types:
(1) select
(2) poll
(3) epoll,
its principle and implementation will not be described in detail.

Signal Driven I/O

Signal-driven IO is to establish a SIGIO signal association with the kernel and set a callback. When the kernel has an FD ready, it will send a SIGIO signal to notify the user. During this period, the user application can perform other services without blocking and waiting.
Phase 1:
①The user process calls sigaction, registers the signal processing function
②The kernel returns successfully, and starts to monitor FD
③The user process does not block and wait, and can perform other services
④When the kernel data is ready, call back the SIGIO processing function of the user process
Phase 2:
① Receive SIGIO callback signal
②Call recvfrom, read
③Kernel copies data to user space
④User process processes data
signal to drive I/O. There are obvious shortcomings. When there are a large number of IO operations, there are many signals, and the SIGIO processing function cannot Timely processing may cause signal queue overflow, and the performance of frequent signal interaction between kernel space and user space is also low.

Extra step I/O

The whole process of asynchronous IO is non-blocking. After the user process calls the asynchronous API, it can do other things. The kernel waits for the data to be ready and copies it to the user space before submitting the signal to notify the user process. (This process is like the interrupt mechanism of the CPU. After the user process releases the task, it can do other things. After the kernel finishes processing, the kernel will signal the user process.) The difference here is that asynchronous
IO Both signal-driven IO and signal-driven IO are a bit like interrupt mode, but the difference between the two is that signal-driven IO sends an interrupt signal at the end of the first stage, and the second stage requires the participation of user processes; while asynchronous IO realizes real Asynchronous, the kernel will send an interrupt signal only after everything has been processed (the data is copied back to user space)

Phase 1:
① The user process calls aio_read to create a signal callback function
② The kernel waits for the data to be ready
③ The user process does not need to block and can do anything
Phase 2:
① The kernel data is ready
② The kernel data is copied to the user buffer
③ The copy is completed, and the kernel submits the signal Trigger the callback function in aio_read
④ user process to process data

The disadvantage of asynchronous IO is that in high-concurrency scenarios, because the IO efficiency is low, many tasks will be accumulated in the system, which will easily lead to system crashes (it can be solved by current limiting, etc., but the implementation method is cumbersome and complicated).

Guess you like

Origin blog.csdn.net/hhhlizhao/article/details/131797057