'strace' 修复挂起的进程。

6

我有一个单线程的Unix进程,通过TCP与其他进程通信。

问题如下。当我启动进程时,它会挂起(没有忙循环),直到我杀死它。

有趣的是,一旦我使用strace进行附加,它就会继续以期望的行为运行,就好像根本没有任何问题一样(总是可以重现)。

这种行为的原因是什么?strace对进程状态有什么影响?


strace改变行为的原因是我们使用了有缺陷的openonload。一旦我们附加了strace,堆栈就被移回内核,问题就解决了。


如果代码是多线程的,可以通过控制进程来避免竞争条件,在代码执行的不同点强制进行上下文更改,而不是在代码本地运行时发生。对于存在问题的多线程代码运行调试器有时会导致代码未显示问题 - 对我而言。 - jim mcnamara
真的,但是楼主说“单线程” :) - loreb
我有一个类似的情况...如果我附加到strace,挂起的进程就可以正常工作。有人能详细解释一下吗? - ernesto
4
现在有一篇关于此事的文章:https://ayende.com/blog/198849-C/production-postmortem-the-heisenbug-server?Key=1eeda567-02a8-4bbb-b90f-557523973233 - D.R.
3个回答

3
许多年后,可能出现完全不同的根本原因,这篇博客文章解释了为什么附加跟踪器可能会修复挂起的系统调用:https://ayende.com/blog/198849-C/production-postmortem-the-heisenbug-server?Key=1eeda567-02a8-4bbb-b90f-557523973233。看起来运行strace(或任何其他使用ptrace系统调用的工具)可能会导致“挂起”的系统调用返回(并带有EINTR退出代码)。
引用ptrace man page

Some system calls return with EINTR if a signal was sent to a

tracee, but delivery was suppressed by the tracer. (This is very typical operation: it is usually done by debuggers on every attach, in order to not introduce a bogus SIGSTOP). As of Linux 3.2.9, the following system calls are affected (this list is likely incomplete): epoll_wait(2), and read(2) from an inotify(7) file descriptor. The usual symptom of this bug is that when you attach to a quiescent process with the command

   strace -p <process-ID>

then, instead of the usual and expected one-line output such as

   restart_syscall(<... resuming interrupted call ...>_

or

   select(6, [5], NULL, [5], NULL_

('_' denotes the cursor position), you observe more than one line. For example:

    clock_gettime(CLOCK_MONOTONIC, {15370, 690928118}) = 0
    epoll_wait(4,_

What is not visible here is that the process was blocked in epoll_wait(2) before strace(1) has attached to it. Attaching caused epoll_wait(2) to return to user space with the error EINTR. In this particular case, the program reacted to EINTR by checking the current time, and then executing epoll_wait(2) again. (Programs which do not expect such "stray" EINTR errors may behave in an unintended way upon an strace(1) attach.)


你能在这里做个总结吗?链接迟早会失效。 - Peter Mortensen
实际上,ptrace手册页是摘要。但我添加了一句话来总结它。 - Fabian Schmied

0

很可能strace输出只是减慢了进程,使死锁不太可能发生。我以前见过这种情况,当时使用strace或添加其他调试打印或调试调用时也会发生。

死锁通常在多线程交互中最常见。但在你的情况下,你有多个进程。如果每次strace释放进程,那么我想你打开套接字或套接字握手的方式就是出问题的地方。我认为在套接字上缓冲和阻塞可能会使你陷入进程死锁状态。

类似的问题,但是针对的是多线程进程,在线程之间死锁而不是在不同进程之间死锁:使用strace修复内存挂起问题

很难提供一般性的示例,特别是因为不知道你的不同进程在做什么或是否以某种方式共享资源?我会尝试……

  1. 一个需要保护的对象/资源的示例:
    一个进程开始对一个对象进行更改(例如向列表/数据库表中添加项目)
    另一个进程开始迭代列表/表。
    有一个进程迭代循环被混淆并永远不会退出,或者做一些更糟糕的事情,比如写入无效的内存。

  2. 对象/资源由互斥锁保护的示例
    两个资源问题的经典简单死锁。 ~比哲学家就餐问题更简单
    一个线程/进程获取对象A上的互斥锁,执行一些工作。
    另一个线程/进程获取对象B上的互斥锁,执行一些工作。
    同一个线程/进程需要更新对象A,等待A的互斥锁。
    原始线程/进程需要访问对象B,等待B的互斥锁。
    . . . . . . . . . . . . @ . . . . . . . . . . .
    除了风声和风滚草在景象中滚动之外,一片寂静。
    死锁。


0

我只遇到过一次这个问题,它与信号处理有关。这是单线程代码中竞态条件的一个来源。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接