写了个异步日志

来源:互联网 发布:mac os x 10.6.8 升级 编辑:程序博客网 时间:2024/05/16 08:41

主要实现:简单的异步日志,工作线程只需把日志消息写入缓冲,不必阻塞与耗时的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
原创粉丝点击