【问题标题】:Fetching from std::queue is CPU intensive in a multithreaded environment在多线程环境中从 std::queue 获取是 CPU 密集型的
【发布时间】:2020-08-07 12:54:57
【问题描述】:

请看下面的多线程 C++ 伪代码。(没有 C++11)

Mutex mtx;

addToQueueFromManyThreads()
{
    mtx.lock;
    pushTowriteQueue();
    mtx.unLock();
}

run()  
{
   std::string nextMessage = fetchNext();

   while ( !nextMessage.empty()  )
   {
       //  writeToFile( nextMessage );
       //  (void)SchedYield();
       nextMessage = fetchNext();   
    }
    delay( 25 ms );
}


std::string CTraceFileWriterThread::fetchNext() 
{
    std::string message;
 
    mtx.lock;
    if( !writeQueue.empty() )
    {
      message = writeQueue.front();
      writeQueue.pop();
    }
    mtx.unLock();

    return message;
}
  1. 使用或不使用“writeToFile”或“SchedYield”没有太大区别。
  2. 我在低优先级线程上运行
  3. 由于上面的代码导致CPU占用过多,整个进程被杀死
  4. addToQueueFromManyThreads 被应用程序广泛调用,因为每秒要记录大量消息

此时,我想知道我是否使用了正确的数据结构,并且我已经尽我所能尝试了所有选项。感谢您对可能发生的事情的任何帮助。

【问题讨论】:

  • 我注意到您的delay()run() 的while 循环之外。这似乎是一个错误。但是除了使用条件变量而不是手动检查之外,您正在运行多少个线程?数据传入的速度有多快?
  • 请尽可能提供编译代码。伪代码用处不大。
  • @metal ,事实上我也尝试过使用条件变量,但消息太快了,这并不重要。它会在一秒钟内发出 50-60 次信号。所以,我想我会简化,看看到底发生了什么。我们有大约 40 个正在运行的线程正在推送到队列
  • 您有多少个处理器? 40 个线程听起来对于上下文切换来说开销很大,这可能会使问题变得更糟,而不是给你更多的吞吐量。条件变量而不是手动让步可以通过一次只激活一个等待线程来最小化上下文切换的数量。
  • 机器老旧,处理能力不大。虽然我没有具体细节。但是,仅仅有条件变量是没有帮助的。

标签: c++ multithreading queue cpu-usage c++98


【解决方案1】:

run() 的逻辑有缺陷。它有效地不间断地运行,一遍又一遍地检查队列中是否有消息要处理。如果没有,它有什么作用?它再次检查,微弱地希望有一条新消息在最后一毫秒左右到达。这就是为什么您将 CPU 负载推高的原因。事实上,它大部分时间都花在一个锁定的互斥体上,防止其他想要向队列添加新消息的执行线程锁定互斥体,这一事实也无济于事。

正确实现这一点的教科书解决方案是简单地使用条件变量,然后等待它。条件变量在 C++11 之前就存在,并且在 POSIX 中可用。这将使执行线程进入睡眠状态,完全停止所有 CPU 活动,直到在向队列中添加新消息后,另一个执行线程发出了条件变量的信号。如果不使用条件变量,您无法解决此问题,没有其他实用的替代方案。

每本涵盖执行线程和 POSIX 的 C++ 教科书都解释了如何使用条件变量,我将在其中指导您获取更多信息和示例,尤其是因为显示的代码是伪代码。您应该花一些时间查看本材料,以便理解和学习使用条件变量及其语义的正确方法。使用不当无济于事,而且可能会使事情变得更糟。

【讨论】:

  • 我几乎建议查看基于 C++11 条件变量的线程安全队列。应该可以将其翻译回 POSIX。
  • 感谢您的回答,但我已经尝试使用条件变量,但消息流入速度如此之快,这并不重要。我们有大约 40 个线程要推送到有问题的队列中。正如您所提到的,持有互斥锁并阻塞其他线程可能是问题所在。
  • 如果你正确地使用了条件变量,当run() 正在等待新消息时,互斥锁将不会被锁定并阻塞其他线程。
  • 您应该发布一个新问题。每个 stackoverflow.com 问题一个问题。
  • 感谢您的回答。正如你所提到的,我已经发布了一个带有正确代码的问题stackoverflow.com/questions/63305427/…
猜你喜欢
  • 1970-01-01
  • 2020-10-11
  • 1970-01-01
  • 1970-01-01
  • 2020-06-16
  • 2012-09-24
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
相关资源
最近更新 更多