Killing Infinite Loops in Java/Clojure
Asked Answered
K

4

6

Responses to some "potential answers"

  • You should sprinkle "interrupts" into your threads

    I don't write my code with the intention of it being a long process / infinite loop; it's just that in development, I accidently write code that happens to be infinite loops, thus I can never plan beforehand to put "check if thread got interrupted" into the code.

Question:

As I get more familiar with Java/Clojure/Swank and incremental code development. I find it very easy for me to accidentally write a clojure function that ends up being an infinite loop -- and run it. This then goes ahead, and pegs the JVM, causing the fans on my laptop to spin up -- and basically, I have to kill the entire JVM to just get rid of one run away thread.

Now, is there anyway I can somehow kill these clojure threads safely? I am well aware that Thread.stop has various unsafe consequences (like holding locks that other threads may need, etc ...) -- however, these here are clojure functions that are infinite looping -- and I'm doing them outside of any STM -- so I'm wondering if there's some way to kill these threads safely.

Thanks!

Kashmir answered 20/4, 2012 at 23:6 Comment(8)
You'd have to come up for a definition as to what an infinite loop is first.Wardroom
(println (range)) is an infinite loop.Kashmir
That's an example, not a definitionChyle
The point is generally detecting infinite loops is akin to solving the Halting problem which is technically impossible.Calamine
Are you using Eclipse or something? Eclipse generally lets you terminate the tested program without hanging...?Nucleoside
The problem is NOT detection of infinite loops. The problem is: given a thread that is infinite looping, how do I safely kill it?Kashmir
i think this is a problem related to your environment (swank) so i've added those tags. for me, in intellij idea, i just click on the button that zaps the process running the repl; i suspect swank has something similar (i added slime too - i think you use sawnk with slime?)Saturniid
Yes. I start the repl with "lein swank" and connect to use with "M-x slime-connect." I fully control the environment, so I can modify either of those to make things work.Kashmir
I
8

I don't think a fully complete answer exists, though there are some incomplete but still useful things to do:

  • First I hit ctrl-c ctrl-c from the repl which kills the foreground thread which gets 99% of my common mistakes.
  • Then if that fails I go for the terminal and the kill command.
  • after that its M-x slime-quit-lisp, clojure-jack-in
Isomagnetic answered 21/4, 2012 at 1:6 Comment(2)
This is not perfect, but this is as good as I believe will be practical.Kashmir
since this was posted the slime commands changed to cider, now it's cider-jack-inIsomagnetic
S
2

What about writing a macro to create these loops and that macro can inject code in the loop steps to periodically check for something that indicates it to exit out of loop, like the existence of a temporary file on /tmp. So basically to exit the infinite loop you would just need to create that temporary file.

Splat answered 21/4, 2012 at 6:24 Comment(1)
I think this is the best solution as it doesn't depend on any particular development environment. You can replace the standard clojure.core loop/recur with custom ones that check an atom and/or use a built in counter or timer to limit the loop and it can even display debug information such as current loop state when it is stopped.Behest
S
0

Theoretically, as mentioned in the comments, this is a very difficult problem to truly solve.

The best hope for a practical solution...

I'm assuming here that you want a more reliable and safe way of killing and analyzing activity in the clojure threads which are running . . . And for this, JPS is the way to go, since JPS monitors all Java processes, including anything you do in standard clojure.

I always use JPS for this sort of thing, because it can be used to show the process names of specific java classes INCLUDING the class names... The ability to know the class which initially invoked a process gives you a pretty precise idea of "what" youre actually killing.

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

In this case, since "lein repl" (the clojure repl) is started via jline (the main class being ConsoleRunner), we can see it as such.

If you really need to see the details, you can pick any of these processes and call them with jstack :

$>jstack 51866

"Gang worker#0 (Parallel GC Threads)" prio=9 tid=101802800 nid=0x1017f9000 runnable

"Gang worker#1 (Parallel GC Threads)" prio=9 tid=101803800 nid=0x102301000 runnable

"Concurrent Mark-Sweep GC Thread" prio=9 tid=10184e000 nid=0x1093f0000 runnable "VM Periodic Task Thread" prio=10 tid=1018a4000 nid=0x10a310000 waiting on condition

"Exception Catcher Thread" prio=10 tid=101802000 nid=0x100704000 runnable JNI global references: 137

In this case, you'll be able to get a feel for wether or not there are any real issues in your threads, identify them precisely , and kill them with confidence, etc...

Shanna answered 21/4, 2012 at 3:44 Comment(0)
N
0

In Eclipse/Counterclockwise beta there's an option to manually stop running (out of control) threads, without having to stop the REPL. I love that feature for the same reason you would like to have it.

It makes use of NREPL 0.2.0 beta, I think through clojure.tools.nrepl.middleware.interruptible-eval. Not only the Eclipse/CCW NREPL 0.2.0 client, but also the latest version of REPL-y should support this function (default CTRL-C for stopping thread, CTRL-D for stopping REPL).

Nolin answered 21/4, 2012 at 12:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.