【问题标题】:Killing Infinite Loops in Java/Clojure在 Java/Clojure 中杀死无限循环
【发布时间】:2012-04-20 23:06:58
【问题描述】:

对一些“潜在答案”的回应

  • 你应该在你的线程中加入“中断”

    我编写代码的目的不是为了让它成为一个漫长的过程/无限循环;只是在开发过程中,我不小心编写了恰好是无限循环的代码,因此我永远无法事先计划将“检查线程是否被中断”放入代码中。

问题:

随着我越来越熟悉 Java/Clojure/Swank 和增量代码开发。我发现我很容易不小心编写了一个最终成为无限循环的 clojure 函数并运行它。然后继续进行,并锁定 JVM,导致我的笔记本电脑上的风扇旋转 - 基本上,我必须杀死整个 JVM 才能摆脱一个失控的线程。

现在,无论如何我可以以某种方式安全地杀死这些 clojure 线程吗?我很清楚 Thread.stop 具有各种不安全的后果(例如持有其他线程可能需要的锁等...)——但是,这里的这些 clojure 函数是无限循环的——并且我在任何 STM 之外执行它们——所以我想知道是否有某种方法可以安全地杀死这些线程。

谢谢!

【问题讨论】:

  • 您必须首先定义什么是无限循环。
  • (println (range)) 是一个无限循环。
  • 重点是检测无限循环类似于解决技术上不可能的停机问题。
  • 您使用的是 Eclipse 还是什么? Eclipse 一般允许你终止被测程序而不挂起...?
  • 问题是没有检测到无限循环。问题是:给定一个无限循环的线程,我如何安全地杀死它?

标签: java multithreading clojure slime swank


【解决方案1】:

我认为不存在完全完整的答案,尽管有一些不完整但仍然有用的事情要做:

  • 首先我从repl 中点击ctrl-c ctrl-c,它会杀死前台线程,这会导致我99% 的常见错误。
  • 如果失败,我会使用终端和kill 命令。
  • 之后是M-x slime-quit-lispclojure-jack-in

【讨论】:

  • 这并不完美,但我相信它是实用的。
  • 自从发布后,粘液命令更改为 cider,现在它是 cider-jack-in
【解决方案2】:

如何编写一个宏来创建这些循环,并且该宏可以在循环步骤中注入代码以定期检查表明它退出循环的内容,例如 /tmp 上是否存在临时文件。所以基本上要退出无限循环,你只需要创建那个临时文件。

【讨论】:

  • 我认为这是最好的解决方案,因为它不依赖于任何特定的开发环境。您可以将标准 clojure.core loop/recur 替换为检查原子和/或使用内置计数器或计时器来限制循环的自定义循环,它甚至可以在停止时显示调试信息,例如当前循环状态。
【解决方案3】:

在 Eclipse/逆时针测试版中,有一个选项可以手动停止运行(失控)线程,而无需停止 REPL。我喜欢该功能的原因与您想要拥有它的原因相同。

它使用 NREPL 0.2.0 beta,我认为是通过 clojure.tools.nrepl.middleware.interruptible-eval。不仅 Eclipse/CCW NREPL 0.2.0 客户端,最新版本的 REPL-y 都应该支持这个功能(默认 CTRL-C 停止线程,CTRL-D 停止 REPL)。

【讨论】:

    【解决方案4】:

    理论上,正如cmets中提到的,这是一个很难真正解决的问题。

    实用解决方案的最大希望...

    我在这里假设您想要一种更可靠、更安全的方式来杀死和分析正在运行的 clojure 线程中的活动。 . .为此,JPS 是可行的方法,因为 JPS 监控所有 Java 进程,包括您在标准 clojure 中执行的任何操作。

    这类事情我总是用JPS,因为它可以用来展示流程 特定 java 类的名称,包括类名......知道 最初调用一个进程的类让你对“你是什么”有一个非常精确的概念 真的杀人了。

    doolittle-5:~ Jpeerindex$ jps -l
    61133 jline.ConsoleRunner
    58998 start.jar
    61161 sun.tools.jps.Jps
    51866 jline.ConsoleRunner
    

    在这种情况下,由于“lein repl”(clojure repl)是通过 jline(主类 作为 ConsoleRunner),我们可以这样看待它。

    如果您确实需要查看详细信息,可以选择其中任何一个进程并使用 jstack 调用它们:

    $>jstack 51866

    “Gang worker#0(并行 GC 线程)”prio=9 tid=101802800 nid=0x1017f9000 可运行

    “Gang worker#1(并行 GC 线程)”prio=9 tid=101803800 nid=0x102301000 可运行

    “并发 Mark-Sweep GC 线程”prio=9 tid=10184e000 nid=0x1093f0000 可运行的“VM 定期任务线程”prio=10 tid=1018a4000 nid=0x10a310000 等待条件

    “异常捕获线程”prio=10 tid=101802000 nid=0x100704000 可运行的 JNI 全局引用:137

    在这种情况下,您将能够感觉到您的线程中是否存在任何实际问题,准确地识别它们,并自信地杀死它们,等等......

    【讨论】:

      猜你喜欢
      • 2011-03-30
      • 2013-08-04
      • 2023-04-06
      • 2021-01-05
      • 1970-01-01
      • 2016-02-29
      • 2016-10-26
      • 2014-01-14
      • 2014-05-07
      相关资源
      最近更新 更多