muduo多线程异步日志学习
以 下 为 个 人 理 解 , 可 能 存 在 错 误 之 处 。 \color{red}{以下为个人理解,可能存在错误之处。} 以下为个人理解,可能存在错误之处。
发送方(前端)
当新来一条日志,发送方的处理代码如下;
void AsyncLogging::append(const char* logline, int len)
{
muduo::MutexLockGuard lock(mutex_);
if (currentBuffer_->avail() > len){
// most common case: buffer is not full,copy data here
currentBuffer_->append(logline, len);
}else{ // buffer is full, push it, and find next spare buffer
buffers_.push_back(std::move(currentBuffer_));
if (nextBuffer_){ // is there is one already,use it
currentBuffer_ = std::move(nextBuffer_);
}
else{ // allocate a new one
currentBuffer_.reset(new Buffer); // Rarely happens
}
currentBuffer_->append(logline, len);
cond_.notify();
}
}
append()函数对应的流程图:
这里的几个变量:
- currentBuffer_: 指针,指向发送方当前正在使用的缓冲区;
- nextBuffer_:指针,指向备份缓冲区,也就是一个准备好的内存空间;
- Buffers_:一个容器,类似于Vector,将写满了的或者不足以写当前日志的currentBuffer放进来,等待后端将Buffers_所有的元素(日志块)写入文件。
示意图:
发送方(后端)
void AsyncLogging::threadFunc()
{
BufferPtr newBuffer1(new Buffer);
BufferPtr newBuffer2(new Buffer);
BufferVector buffersToWrite;
while (running_)
{
// swap out what need to be written, keep CS short
{
muduo::MutexLockGuard lock(mutex_);
if (buffers_.empty()) // unusual usage!
{
cond_.waitForSeconds(flushInterval_);
}
buffers_.push_back(currentBuffer_.release()); // 移动,而非复制
currentBuffer_ = boost::ptr_container::move(newBuffer1); // 移动,而非复制
buffersToWrite.swap(buffers_); // 内部指针交换,而非复制
if (!nextBuffer_)
{
nextBuffer_ = boost::ptr_container::move(newBuffer2);
}
}
// output buffersToWrite to file
// re-fill newBuffer1 and newBuffer2
}
// flush output
}
threadFunc函数流程图