我写了一个网络记录器,它在单独的线程中工作。这个想法是允许应用程序推送任何数量的数据,记录器应该单独处理它,而不会减慢主线程的速度。伪代码看起来像:
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对多)。解释得很好。