我正在开发一个嵌入式Linux系统(3.12.something),经过一段随机的时间后,我们的应用程序开始占用CPU。我在我们的应用程序上运行strace
,当问题发生时,我在strace
输出中看到了很多与此类似的行:
[48530666] futex(0x485f78b8, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.009002>
我很确定这是我正在寻找的吸烟枪,而且还有某种类型的比赛。但是,我现在需要弄清楚如何识别代码中试图获取此互斥锁的位置。我怎样才能做到这一点?我们的代码使用GCC编译,并在其中包含调试符号。
我当前的想法(我还没有尝试过)是在尝试抓取系统中的任何互斥锁之前将字符串打印到stdout并刷新,期望字符串将在strace抱怨获取之前打印出来锁定......但代码中有很多地方需要像这样进行检测。
编辑:我刚才意识到的另一个奇怪的事情是,我们的程序在运行后经过一段随机时间(5分钟到5小时之间的任何时间)都没有开始占用CPU。在此期间,发生了零futex
个系统调用。他们为什么突然开始?从我读过的内容来看,我认为可能它们在用户空间中被正确使用,直到出现故障并回到制作futex()
系统调用...
有什么建议吗?
答案 0 :(得分:0)
如果您永久性地经常从不同的线程锁定互斥锁,例如,例如一个保护全局记录器,你可能会导致一个所谓的线程护航。直到两个线程争用锁定才会出现此问题。第一个获取锁定并保持一小段时间,然后,当它需要第二次锁定时,它会被抢占,因为第二个已经等待。第二个做同样的事情。每个线程可用的时间片突然缩短到两次锁定尝试之间的时间,导致许多上下文切换和相应的减速。此外,除了一个线程之外的所有线程都始终在互斥锁上被阻塞,从而有效地禁用任何并行执行。
为了解决这个问题,请让您的线程合作而不是竞争资源。对于记录器的上述示例,请考虑例如使用线程本地存储的每个线程的条目或单独队列的无锁队列。
关于futex()调用,我们的想法是轮询原子标志,并在一些轮换后使用实际的OS互斥锁。原子标志可用,而无需在用户空间和内核空间之间进行昂贵的切换。对于较长的中断,使用内核抢占(使用futex()
)可以避免使用轮询阻止CPU。这解释了为什么程序在正常操作中不需要任何futex()
次调用。
答案 1 :(得分:0)
你,此时基本上需要生成核心文件。
然后你可以在GDB中加载program + core并查看它
man gcore
或
generate-core-file
在此期间,发生了零互助系统调用。他们为什么突然开始?
这是因为通过futex实现的无争议互斥体不会进行系统调用,只进行原子增量,纯粹是在用户空间中。系统调用只能看到CONTESTED锁