• 缓冲区与C库函数的实现


    目录

    一、缓冲区

    二、C库函数的实现


    一、缓冲区

    缓冲区本质就是一块内存,而缓冲区存在的意义本质是提高使用者(用户)的效率【把缓冲区理解成寄送包裹的菜鸟驿站】

    缓冲区的刷新策略

    1. 无缓冲(立即刷新)

    2. 行缓冲(行刷新)

    3. 全缓冲(缓冲区满了,再刷新) ---》 进程退出属于全刷新的一种

    4. 特殊清空:用户强制刷新

    显示器文件一般采用行刷新,磁盘上的文件一般采用全刷新

    现象:

    如何理解上述现象呢???

    1.首先,显示器文件刷新方式是行刷新,且fork之前所有的代码都带\n, 所以fork之前,所有代码都被刷新了!而重定向到log.txt, 本质是访问了磁盘文件,刷新方式从行缓冲变成了全缓冲!这意味着缓冲区变大,实际写入的数据不足以把缓冲区写满,fork执行时,数据依然在缓冲区中!

    2. 而我们发现,无论如何, 系统调用只打印了一次,而加了fork之后,重定向到文件中的函数打印了两次,因为这些函数底层封装的是write系统调用,这就说明目前我们所说的缓冲区和操作系统没有关系, 只能和C语言有关系! 我们日常用的最多的缓冲区就是C语言提供的缓冲区!

    3.C/C++提供的缓冲区,里面保存的是用户的数据,属于当前进程的运行时自己的数据;而如果通过系统调用把数据写入到了OS内部,那么数据就不属于用户了!

    4.当进程退出时,要刷新缓冲区,刷新缓冲区也属于写入操作,而fork创建子进程后,父子进程任何一方要对数据写入时,都要发生写时拷贝,所以数据出现两份!而系统调用只有一份,是因为系统调用是在库之下的,不适用C语言提供的缓冲区,直接将数据写入了OS, 不属于进程了,所以不发生写时拷贝,数据只有1份!

    上述C语言提供的缓冲区位于FILE结构体内部!!!

    二、C库函数的实现

    1. #include "mystdio.h"
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define DEL_MODE 0666
    10. myFILE* my_fopen(const char *path, const char *mode)
    11. {
    12. int fd = 0;
    13. int flag = 0;
    14. if(strcmp(mode, "r") == 0)
    15. {
    16. flag |= O_RDONLY;
    17. }
    18. else if(strcmp(mode, "w") == 0)
    19. {
    20. flag |= (O_CREAT | O_WRONLY | O_TRUNC);
    21. }
    22. else if(strcmp(mode, "a") == 0)
    23. {
    24. flag |= (O_CREAT | O_WRONLY | O_APPEND);
    25. }
    26. else
    27. {
    28. //do nothing
    29. }
    30. if(flag & O_CREAT)
    31. {
    32. fd = open(path, flag, DEL_MODE);
    33. }
    34. else
    35. {
    36. fd = open(path, flag);
    37. }
    38. if(fd < 0)
    39. {
    40. errno = 2;
    41. return NULL;
    42. }
    43. myFILE* fp = (myFILE*)malloc(sizeof(myFILE));
    44. if(!fp)
    45. {
    46. errno = 3;
    47. return NULL;
    48. }
    49. fp->flag = FLUSH_LINE;
    50. fp->end = 0;
    51. fp->fileno = fd;
    52. return fp;
    53. }
    54. int my_fwrite(const char* s, int num, myFILE* stream)
    55. {
    56. memcpy(stream->buffer+stream->end, s, num);
    57. stream->end += num;
    58. //判断是否需要刷新
    59. if((stream->flag & FLUSH_LINE) && stream->end > 0 && stream->buffer[stream->end-1] == '\n')
    60. {
    61. my_fflush(stream);
    62. }
    63. return num;
    64. }
    65. int my_fflush(myFILE* stream)
    66. {
    67. if(stream->end > 0)
    68. {
    69. write(stream->fileno, stream->buffer, stream->end);
    70. //fsync(stream->fileno); //把数据刷新到内核中
    71. stream->end = 0;
    72. }
    73. return 0;
    74. }
    75. int my_fclose(myFILE* stream)
    76. {
    77. my_fflush(stream);
    78. return close(stream->fileno);
    79. }

  • 相关阅读:
    计算机网络那些事之 MTU 篇
    华为OD机试真题-求最小步数-2023年OD统一考试(B卷)
    Kafka-exporter监控消费速度与生产速度差异规则
    二、深度测试(Z Test)
    【单目3D目标检测】SMOKE + MonoFlex 论文解析与代码复现
    嵌入式笔试面试刷题(day15)
    【TS】函数重载--可选参数--默认参数
    在 .NET 应用程序中运行 JavaScript
    力扣刷题 day43:10-13
    低代码掀起“数字革命”,引领制造业数字化转型
  • 原文地址:https://blog.csdn.net/m0_74126249/article/details/136660142