请在2024年Clojure状态调查中分享您的想法!

欢迎!有关如何使用本页面,请参阅关于页面获取更多信息。

0
ClojureScript

退出并尝试使用相同的JVM / REPL环境重新连接可能会锁定

`
$ clj
Clojure 1.9.0
user=> (require '[cljs.repl :as repl])
nil
user=> (require '[cljs.repl.browser :as browser])
nil
user=> (def env (browser/repl-env))

'user/env

user=> (repl/repl env)
ClojureScript 1.10.339
cljs.user=> 3
3
cljs.user=> :cljs/quit
nil
user=> (repl/repl env)
`

此时,系统已经锁定。以下是线程堆栈

`
$ jstack 97709
2018-10-13 13:26:33
完整的线程转储 Java HotSpot(TM) 64-Bit Server VM (25.172-b11 混合模式)

"Attach Listener" #156 daemon priority 9 os_prio=31 tid=0x00007ff1d4a14000 nid=0x9f0b waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"clojure-agent-send-off-pool-1" #14 priority 5 os_prio=31 tid=0x00007ff1d4963800 nid=0x4003 waiting on condition [0x000070000cd57000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c1859760> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"clojure-agent-send-off-pool-0" #13 priority 5 os_prio=31 tid=0x00007ff1d41e9800 nid=0x4203 waiting on condition [0x000070000cc54000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c1859760> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"process reaper" #12 daemon priority 10 os_prio=31 tid=0x00007ff1d4967800 nid=0x3c03 waiting on condition [0x000070000cb51000]
java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x00000006c209c4a8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

"Service Thread" #8 daemon priority 9 os_prio=31 tid=0x00007ff1d206a800 nid=0x4403 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #7 daemon priority 9 os_prio=31 tid=0x00007ff1d1814000 nid=0x3603 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #6 daemon priority 9 os_prio=31 tid=0x00007ff1d2057800 nid=0x3503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon priority 9 os_prio=31 tid=0x00007ff1d2058800 nid=0x4703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" #4 daemon priority 9 os_prio=31 tid=0x00007ff1d2057000 nid=0x490b runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon priority 8 os_prio=31 tid=0x00007ff1d2018000 nid=0x5103 in Object.wait() [0x000070000c411000]
java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c01466f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000006c01466f8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon priority 10 os_prio=31 tid=0x00007ff1d2017800 nid=0x2e03 in Object.wait() [0x000070000c30e000]
java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)
- waiting on <0x00000006c0146980> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000006c0146980> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 priority 5 os_prio=31 tid=0x00007ff1d2005000 nid=0x2103 waiting on condition [0x000070000bcfa000]
java.lang.Thread.State: WAITING (parking)

at sun.misc.Unsafe.park(Native Method)
- parking to wait for  <0x0000000792c08ed8> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at clojure.core$promise$reify__8144.deref(core.clj:7029)
at clojure.core$deref.invokeStatic(core.clj:2312)
at clojure.core$deref.invoke(core.clj:2298)
at cljs.repl.browser$browser_eval.invokeStatic(browser.clj:283)
at cljs.repl.browser$browser_eval.invoke(browser.clj:272)
at cljs.repl.browser.BrowserEnv._evaluate(browser.clj:373)
at cljs.repl$evaluate_form.invokeStatic(repl.cljc:568)
at cljs.repl$evaluate_form.invoke(repl.cljc:498)
at cljs.repl$repl_STAR_.invokeStatic(repl.cljc:946)
at cljs.repl$repl_STAR_.invoke(repl.cljc:855)
at cljs.repl$repl.invokeStatic(repl.cljc:1100)
at cljs.repl$repl.doInvoke(repl.cljc:1030)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at user$eval2535.invokeStatic(NO_SOURCE_FILE:8)
at user$eval2535.invoke(NO_SOURCE_FILE:8)
at clojure.lang.Compiler.eval(Compiler.java:7062)
at clojure.lang.Compiler.eval(Compiler.java:7025)
at clojure.core$eval.invokeStatic(core.clj:3206)
at clojure.core$eval.invoke(core.clj:3202)
at clojure.main$repl$read_eval_print__8572$fn__8575.invoke(main.clj:243)
at clojure.main$repl$read_eval_print__8572.invoke(main.clj:243)
at clojure.main$repl$fn__8581.invoke(main.clj:261)
at clojure.main$repl.invokeStatic(main.clj:261)
at clojure.main$repl_opt.invokeStatic(main.clj:325)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)

"VM Thread" os_prio=31 tid=0x00007ff1d1811000 nid=0x2d03 runnable

"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ff1d2010800 nid=0x1e07 runnable

"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ff1d2802800 nid=0x1d03 runnable

"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ff1d3006800 nid=0x2b03 runnable

"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ff1d2803000 nid=0x5403 runnable

"VM Periodic Task Thread" os_prio=31 tid=0x00007ff1d206b000 nid=0x3903 waiting on condition

JNI global references: 248
`

2 答案

0
_评论者:potetm_

我认为这里的问题是有关{{cljs.repl.server/connq}}连接的竞争条件。当它似乎正常工作时,流程如下

1) 退出 cljs repl(通过{{:cljs/quit}})
2) {{connq}}仍然持有对已失效连接的引用
3) 启动一个新的 repl,它将经历{{setup}}
4) 浏览器发送它的`:ready`请求,这调用{{(.clear connq)}}
5) repl 初始化调用其 `init` 函数(使用 {{connq}} 中的连接评估一个形式)

然而,如果4和5被调换(这可能会发生,因为这取决于浏览器初始请求的时间),你会收到仍然在{{connq}}中的失效连接,导致你无限期地挂起。

我的问题是:我们为什么不应该在浏览器 repl 的 {{tear-down}} 中清除 {{connq}}?
0
...