I/O buffer management for background development and I/O buffer for background Development
In Linux I/O, the write prototype is ssize_t write (int filedes, const void * buff, size_t nbytes );
When you call write to write data, write will directly return the data after the call is complete, but the disk is a slow device, and the operating system will save the data in the buffer zone of the kernel, write Data asynchronously to the disk. Of course, if the system goes down at this time, data will be lost. Write is a system call, and each call will fall into the kernel. Therefore, selecting a suitable block length buffsize and minimizing its call can optimize the efficiency. In the standard IO of ansi c, we call printf/fprintf/fputs to process the data in a stream. We only need to write the data to the stream, instead of selecting a buffsize like write, the standard IO library helps us deal with a lot of details, such as buffer allocation to optimize the length of IO execution. This will reduce the number of wirte/read system calls and improve efficiency. But at the same time, another problem will be introduced: Data Copying. For example, when the fgets and fputs functions are used, the buffer usually needs to go through two times: one is the standard IO buffer, another time is the kernel buffer that calls read and write. But in general, the use of standard IO is simpler than system IO, and the efficiency is equivalent.
Standard IO provides three types of Buffers: Full cache, row cache, and no cache. Full cache takes the initiative to flush when the buffer is full, which is usually used for IO of a disk file. The row cache will flush when a line break is encountered in the buffer, and the buffer will also be flush when the input data needs to be obtained from the standard input and output. The row cache is generally used in interactive terminals. Without caching, it is equivalent to directly writing the system call output. The standard error stream stderr usually does not contain caching, which allows the error information to be displayed as soon as possible. In addition to the default flush condition, the buffer is flush when the fflush function is explicitly called and the program ends normally. You can use setbuf/setvbuf to change the default buffer length. For details, see APUE 5.4.
In a program using standard IO, when we redirect a standard output to a file, the row cache is changed to full cache, in some cases, unexpected errors may occur. For example, when you call printf ("***** \ n") and run the program interactively, will be output normally. However, when the standard output is redirected to a file again, the buffer zone becomes full cache, and printf will not output normally, and the row of data is still in the buffer zone. If you fork another sub-process at this time, when the data space is copied to the sub-process, the buffer data is also copied to the sub-process. Then, if the output is in the sub-process, the content in the buffer will be refreshed to generate some unexpected output.
In network programming, system I/O should be used directly. The introduction of the buffer mechanism to improve the performance of standard I/O increases the complexity of network applications. In a sense, the standard IO stream is full-duplex and can execute input and output at the same time. However, the limitations of streaming and socket may sometimes conflict with each other. (See CSAPP P611)
In some advanced network libraries (such as the muduo Library), the system creates its own Buffer Based on System IO, helping users block some inconvenience caused by system IO, for example, when calling write to send a large amount of data, the application layer needs to wait when the sending buffer is full, and the packets and data reception speed are slow when the read receives the data. When the application layer buffer is added, the network library processes these implementation details to simplify user operations.
Linux also provides the zero copy technology to reduce memory copying and improve efficiency. We know that the use of read/write to send data from the disk to the NIC will take four copy operations: when an application needs to access a piece of data, the operating system kernel first checks whether the data is stored in the buffer zone of the operating system kernel address space because of the previous access to the same file, if this data cannot be found in the kernel buffer, the Linux kernel will first read this data from the disk and put it in the buffer zone of the operating system kernel. If the Data Reading operation is completed by DMA, the CPU only needs to manage the buffer zone and create and process the DMA during the DMA data reading process. In addition, the CPU does not need to do more. After the DMA completes the data read operation, the operating system will be notified to perform further processing. The Linux operating system stores the data in the address space of the application requesting the data based on the address space of the specified application address space called by the read system, after the user completes the data operation, the operating system needs to copy the data from the buffer of the user application address space to the kernel buffer related to the network stack, this process also requires CPU usage. After the data copy operation is completed, the data is packaged and then sent to the network interface card. From the above description, we can see that in this traditional data transmission process, data is copied at least four times, even if DMA is used to communicate with hardware, the CPU still needs to access data twice.
(Ps: remember how many times the printf output process has passed through the buffer zone. Now you understand it !)
The zero copy technique can avoid data copying in the buffer zone of the system kernel address space and the buffer zone of the user application address space. Sometimes, applications do not need to access data during data transmission. The transmitted data can be directly sent to the NIC through the kernel instead of being copied to the user's application zone. This improves performance, at this time, the zero copy technology is required. In linux, you can use mmap, sendfile, and splice to achieve zero copy. For more information, see linux's zero copy technology Part 1 Part 2