写了个异步日志

主要实现:简单的异步日志,工作线程只需把日志消息写入缓冲,不必阻塞与耗时的IO操作,由一个背景线程专门负责IO操作。

采用的数据结构,前端为双缓冲区,后端为BlockingQueue,缓冲区的初始化和析构都由背景线程负责,两块缓冲交替使用。

大致的逻辑是:前端使用两块缓冲A和B,A为写缓冲,B为预备缓冲,当写满了A,则交换A和B,并通知背景线程来走B。

背景线程接到前端线程的通知,被唤醒,取走B,放入BlockingQueue,重新准备一块全新的缓冲,放回B,然后去走BlockingQueue中的全部数据,退出临界区,把数据写到硬盘。

还有一种特殊情况,前端写入太快,超过了后端的处理速度。只能自己去申请新的缓冲区了。

这里仅仅贴出临界区的代码

核心类BlockQueue的头文件:


class BlockQueue
{
public:

    BlockQueue();
    ~BlockQueue();
    void append(const string& msg);
    void stop();

private:
    void writtingThread();
    typedef std::shared_ptr<LogBuffer>  BufPtr;
    mutex m_mut;
    BufPtr m_pcurBuf;
    BufPtr m_pnextBuf;
    BufPtr m_pvaildBuf;
    condition_variable m_cond;
    queue<BufPtr> blockingQueue;


    bool isRunning;
    queue<BufPtr> writeQueue;
};

//前端临界区的代码:

void BlockQueue::append(const string& msg){
    mutex::scoped_lock sclock(m_mut);//进入临界区
    if(m_pcurBuf->isValid()){  //第一块缓冲可用,直接写入
        m_pcurBuf->appendLog(msg);
        return;
    }
    else if(m_pnextBuf->isValid()){   //第一块缓冲写满,预备缓冲可用
        m_pcurBuf->setFinishTime();

        std::swap(m_pcurBuf,m_pnextBuf);
        assert(m_pcurBuf->isValid());

        m_pcurBuf->setStartTime();
        m_pcurBuf->appendLog(msg);
        m_cond.notify_one();//通知背景线程
        return;
    }
    else{  //预备缓冲不可用,只能由工作线程自己初始化新缓冲了
        m_pcurBuf->setFinishTime();

        blockingQueue.push(m_pcurBuf);
        m_pcurBuf = make_shared<LogBuffer> ();

        m_pcurBuf->setStartTime();
        m_pcurBuf->appendLog(msg);
        m_cond.notify_one(); //通知背景线程
    }


}



//后端临界区的代码:


void BlockQueue::writtingThread(){
    while(isRunning){
        {//进入临界区
        mutex::scoped_lock sclock(m_mut);
        while(m_pnextBuf->isValid() && blockingQueue.empty())//等待条件成立
            m_cond.wait(sclock);

        if(!m_pnextBuf->isValid()){//取走预备缓冲,交换备用缓冲的指针
            blockingQueue.push(m_pnextBuf);
            assert(m_pvaildBuf->isValid());
            std::swap(m_pvaildBuf,m_pnextBuf);
        }

        while(!blockingQueue.empty()){//把blockingQueue的数据全部取出
            BufPtr ptr = blockingQueue.front();
            blockingQueue.pop();
            writeQueue.push(ptr);
        }
        }//退出临界区

        m_pvaildBuf = make_shared<LogBuffer> (); //初始化新的备用缓冲
        while(!writeQueue.empty()){//IO操作
            BufPtr ptr = writeQueue.front();
            writeQueue.pop();
            ptr->writeToDisk();
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值