我如何从序列输出中确定程序的哪一部分没有获得互斥锁?

How do I determine from strace output what part of my program is failing to acquire a mutex

本文关键字:一部分 程序 输出      更新时间:2023-10-16

我正在一个嵌入式Linux系统(3.12.什么的)上工作,我们的应用程序在一段随机的时间后开始占用CPU。我在应用程序上运行了strace,当问题发生时,我在strace输出中看到了许多类似的行:

[48530666] futex(0x485f78b8, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EAGAIN (Resource temporarily unavailable) <0.009002>

我很确定这就是我要找的确凿证据,这是一场比赛。然而,我现在需要弄清楚如何识别代码中试图获得这个互斥锁的位置。我该怎么做呢?我们的代码是用GCC编译的,里面有调试符号。

我目前的想法(我还没有尝试过)是在试图在我们的系统中抓取任何互斥之前打印出一个字符串到stdout和flush,期望字符串将在strace抱怨获得锁之前打印出来…但是代码中有很多地方需要像这样进行检测。

编辑:我刚刚意识到的另一件奇怪的事情是,我们的程序不会开始占用CPU,直到一些随机的时间已经过去,因为它运行(5分钟到5小时之间的任何地方)。在此期间,发生的 0 futex系统调用。为什么他们突然开始?从我所读到的,我认为也许它们在用户空间中被正确使用,直到某些东西失败并回落到使futex()系统调用…

有什么建议吗?

如果您经常在短时间内永久锁定来自不同线程的互斥锁,例如保护全局记录器的互斥锁,则可能会导致所谓的线程护航。直到两个线程竞争锁时才会出现问题。第一个进程获得锁并持有它一段时间,然后,当它第二次需要锁时,它被抢占,因为第二个进程已经在等待。第二个也是一样。每个线程可用的时间片突然减少到两次锁尝试之间的时间,导致许多上下文切换和相应的速度减慢。此外,除了一个线程之外,所有线程总是在互斥锁上被阻塞,有效地禁用了任何并行执行。

为了解决这个问题,让你的线程合作而不是竞争资源。对于上面的日志记录器示例,可以考虑为条目使用无锁队列,或者使用线程本地存储为每个线程使用单独的队列。

关于futex()调用,这个想法是轮询一个原子标志,在一些旋转之后使用实际的操作系统互斥锁。原子标志不需要在用户空间和内核空间之间进行昂贵的切换。对于较长的中断,使用内核抢占(futex())可以避免轮询阻塞CPU。这解释了为什么程序在正常操作中不需要任何futex()调用。

你,此时基本上需要生成核心文件。

然后你可以在GDB中加载program+core并查看它

man gcore

generate-core-file

在此期间,没有发生futex系统调用。为什么他们突然开始?

这是由于通过futex实现的无争用互斥锁不进行系统调用,只在用户空间进行原子增量。只有当系统调用

时,有争议的锁是可见的