多线程应用程序中的日志队列

Log queue in multithreaded application

本文关键字:日志 队列 应用程序 多线程      更新时间:2023-10-16

我写了一个网络记录器,它在单独的线程中工作。这个想法是允许应用程序推送任何数量的数据,记录器应该单独处理它,而不会减慢主线程的速度。伪代码看起来像:

void LogCoroutine::runLogic()
{
    mBackgroundWorker = std::thread(&LogCoroutine::logic, this);
    mBackgroundWorker.detach();
}
void LogCoroutine::logic()
{
    while (true)
    {
        _serverLogic();
        _senderLogic();
        std::this_thread::sleep_for(std::chrono::milliseconds(10)); // 10ms
    }
}
void LogCoroutine::_senderLogic()
{
    std::lock_guard<std::mutex> lock(mMutex);    
    while (!mMessages.empty() && !mClients.empty())
    {
        std::string nextMessage = mMessages.front();
        mMessages.pop_front();
        _sendMessage(nextMessage);
    }
}

_serverLogic检查套接字中的新连接(对等体),_senderLogic处理带有消息的队列并将其发送给所有连接的对等体。

最后一个功能:推送消息:

void LogCoroutine::pushMessage(const std::string& message)
{
    std::lock_guard<std::mutex> lock(mMutex);
    mMessages.push_back(message);
}

当包裹不经常发送时,一切都很好。应用程序启动时会有一个周期,记录大量信息。并且应用程序会挂起5-10秒,不记录也不会减慢速度。

那么,这个体系结构的瓶颈在哪里呢?也许将每个消息都插入互斥锁是个坏主意?

您的方法基本上是以一定的间隔(10ms)轮询日志事件。这种方法(实际上是忙于等待)的性能不是很好,因为即使没有任何日志消息,您也总是会消耗一些CPU。另一方面,如果新消息到达,您不会通知等待线程。

我建议使用某种阻塞队列来解决这两个问题。内部阻塞队列有互斥锁和条件变量,所以当队列为空时,使用者线程正在等待(而不是忙于循环!)。我认为您的用例非常适合阻塞队列。基于互斥+条件变量,您可以非常容易地实现自己的队列。

用互斥体推送每条消息并不是一个坏主意,无论如何都必须同步它。我只是建议取消投票。

请参阅此示例:如何使用生产者的工作队列&消费者(1对多)。解释得很好。