前言
最近面试,面试官对于muduo库中的双缓冲技术十分感兴趣。所以就开始对这方面的研究。之前已经掌握了双缓冲技术的精髓所在!前端和后端,前端负责将用户的日志写入到缓冲器,后端的线程将已经写好的缓冲区刷入磁盘。这其中刷入磁盘的方面当时没有好好研究,所以现在补上。
本文的很多东西都是自己去做实验推测底层的逻辑,没有去看底层的源码(希望自己能够日后补上源码的分析,去和实验做对比)。所以不是绝对正确的,希望大家有问题指出,一起讨论。
1、问题的提出
操作系统对文件的写入不是直接写入磁盘的。如果每次有信息需要写入,就要去IO磁盘,读取,写入。这样的代价实在是太高。所以常采用缓冲区的技术,对内存中的缓冲区进行写入。等到文件关闭或者用户进行flush刷盘操作的时候才将缓冲区的内容去写入到磁盘中。这样可以大大减少访问磁盘的次数。
对于缓冲区的写入文件关闭和用户的flush操作都可以理解,我好奇的是缓冲区会满吗?满了会刷盘吗?
以下2点是为自己的思考方式:
1、缓冲区会不会满这个问题,主要在于缓冲区满了会不会扩容?
2、缓冲区满了会不会刷盘? 如果缓冲区是固定的,那么肯定要刷盘,如果不刷盘新来的待数据去哪里?
对于第一个问题去查查百度:
由于CPU 与 I/O 设备间速度不匹配。为了缓和 CPU 与 I/O 设备之间速度不匹配矛盾。文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。使用文件缓冲区可减少读取硬盘的次数。
内存区的一定空间应该可以说明缓冲区是固定空间,问题来到了那么缓冲区满了怎么进行刷盘呢?
2、muduo Log日志的源码阅读以及产生的问题
源码的阅读
在AsyncLogging.cc中,主要负责的是后端日志的写入磁盘,写入磁盘的主要操作是:
//AsyncLogging.cc中取出vector<buffer>中的buffer写入磁盘
for (const auto& buffer : buffersToWrite)
{
output.append(buffer->data(), buffer->length());
}
//output是定义的LogFile文件
LogFile output(basename_, rollSize_, false);
每个buffer的大小是4MB,这个4MB相当重要。
去LogFile.cc中查看append操作
void LogFile::append(const char* logline, int len)
{
if (mutex_)
{
MutexLockGuard lock(*mutex_);
append_unlocked(logline, len);
}
else
{
append_unlocked(logline, len);
}
}
调用append_unlocked的函数,LogFIle.cc查看append_unlocked
void LogFile::append_unlocked</