[Linux] Refresh problem of language level buffer and simple simulation implementation


Preface

What we are going to talk about next is the buffer at the language level (C, C++, etc.), which is not the buffer that comes with the kernel of our operating system. Every time we open a file, using C language as an example,C language will allocate a buffer for the file we open to cache the data we read and write. This buffer will be placed in the FILE structure we created, which stores the fields and maintenance of the buffer. information

1. Classification of buffer refresh methods

a. No buffering – direct refresh

b. Line buffering – do not refresh until \n is encountered.

Display writes generally use line buffering

c. Full buffer – refresh only when the buffer is full

File writing generally uses full buffering.The buffer is refreshed when it is full or the program ends

2. Common buffer refresh issues

1. Question

Insert image description here
We redirected the contents of the executable file to log1
Insert image description here
Finally we found that the interface related to C was printed twice. What is the reason?

As we said before, when we write to the file, it is fully buffered, that is, it will be refreshed when the buffer is full or the program ends. What is printed twice is an interface belonging to the C language, which will establish a language-level buffer. area, before we fork, the data written by printf, fprintf, and fwrite are stored in the language-level buffer.A child process is created after fork, and the child process copies the data content of the parent process. Because the buffer is refreshed at this time, the child process will copy the content of the language level buffer of the parent process together.
Therefore, after that, the same data is stored in the language-level buffers of the parent and child processes. When the program ends, the language-level buffers will be refreshed and refreshed to the buffer in the system.

If the child process refreshes first, because the data of the parent process is changed (that is, the language buffer is cleared), a literal copy will occur at this time, and then the data in the child process buffer will be flushed to the system buffer.
In the same way, the parent process will also refresh the buffer. Both the parent and child processes refresh the data and write it into the system buffer, so the file will be written twice.

Write belongs to the system interface. After being called, it will be written directly into the kernel buffer and then written into the hard disk file. There is no concept of language-level buffer, so the file is only written once.

2. Refresh the essence

The essence of user refresh is to redirect to the file (stdout) with file descriptor 1 + write to the kernel buffer. The FILE object belongs to the user, not the operating system. The buffer in FILE belongs to the language level buffer (user-level buffer) area), currently we believe that as long as the data is refreshed to the kernel, the data can be written to the hardware

Insert image description here
These C interfaces are finally written to the kernel buffer. They are essentially system interfaces that call write.

3. Simulation implementation

1.Mystdio.h

#include <string.h>

#define SIZE 1024

#define FLUSH_NOW 1//无缓冲
#define FLUSH_LINE 2//行缓冲
#define FLUSH_ALL 4//全缓冲

typedef struct IO_FILE{
    
    
    int fileno;//文件描述符
    int flag; //刷新方式
    
    char outbuffer[SIZE]; // 简单模拟语言层缓冲区
    int out_pos;//缓冲区当前大小
}_FILE;

_FILE * _fopen(const char*filename, const char *flag);
int _fwrite(_FILE *fp, const char *s, int len);
void _fclose(_FILE *fp);



2.Mystdio.c

#include "Mystdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#define FILE_MODE 0666//文件默认权限

 
_FILE * _fopen(const char*filename, const char *flag)
{
    
    
    assert(filename);
    assert(flag);

    int f = 0;//文件的写入方式
    int fd = -1;//文件描述符
    if(strcmp(flag, "w") == 0) {
    
    
        f = (O_CREAT|O_WRONLY|O_TRUNC);
        fd = open(filename, f, FILE_MODE);
        //获取文件描述符
    }
    else if(strcmp(flag, "a") == 0) {
    
    
        f = (O_CREAT|O_WRONLY|O_APPEND);
        fd = open(filename, f, FILE_MODE);
    }
    else if(strcmp(flag, "r") == 0) {
    
    
        f = O_RDONLY;
        fd = open(filename, f);
    }
    else 
        return NULL;

    if(fd == -1) return NULL;

    _FILE *fp = (_FILE*)malloc(sizeof(_FILE));
    //创建文件指针结构体
    if(fp == NULL) return NULL;

    fp->fileno = fd;
    //fp->flag = FLUSH_LINE;
    fp->flag = FLUSH_ALL;
    fp->out_pos = 0;

    return fp;
}

 
int _fwrite(_FILE *fp, const char *s, int len)
{
    
    
    // "abcd\n"
    memcpy(&fp->outbuffer[fp->out_pos], s, len); // 没有做异常处理, 也不考虑局部问题
    fp->out_pos += len;

    if(fp->flag&FLUSH_NOW)//无缓冲
    {
    
    
        write(fp->fileno, fp->outbuffer, fp->out_pos);
        fp->out_pos = 0;
    }
    else if(fp->flag&FLUSH_LINE)//行缓冲
    {
    
    
        if(fp->outbuffer[fp->out_pos-1] == '\n'){
    
     // 不考虑其他情况
            write(fp->fileno, fp->outbuffer, fp->out_pos);
            fp->out_pos = 0;
        }
    }
    else if(fp->flag & FLUSH_ALL)//全缓冲
    {
    
    
        if(fp->out_pos == SIZE){
    
    
            write(fp->fileno, fp->outbuffer, fp->out_pos);
            fp->out_pos = 0;
        }
    }

    return len;
}

void _fflush(_FILE *fp)//手动刷新缓冲区
{
    
    
    if(fp->out_pos > 0){
    
    
        write(fp->fileno, fp->outbuffer, fp->out_pos);
        fp->out_pos = 0;
    }
}

void _fclose(_FILE *fp)
{
    
    
    if(fp == NULL) return;
    _fflush(fp);
    close(fp->fileno);
    free(fp);
}

3.main.c

#include "Mystdio.h"
#include <unistd.h>

#define myfile "test.txt"

int main()
{
    
    
    _FILE *fp = _fopen(myfile, "a");
    if(fp == NULL) return 1;

    const char *msg = "hello world\n";
    int cnt = 10;
    while(cnt){
    
    
        _fwrite(fp, msg, strlen(msg));
        // fflush(fp);
        sleep(1);
        cnt--;
    }

    _fclose(fp);

    return 0;
}

Guess you like

Origin blog.csdn.net/m0_74774759/article/details/134351406