【问题标题】:Launched process from Scala terminates but Scala waits forever for its termination从 Scala 启动的进程终止,但 Scala 永远等待它的终止
【发布时间】:2019-04-28 22:46:36
【问题描述】:

我以这种方式从 Ammonite 脚本启动一个进程:

scala.sys.process.Process(Seq("executable", "arg1", "arg2")).run().exitValue()

启动的进程正常终止,但它不知道。 通常它工作正常并且检测到进程终止正常。

使用jstack,我已经使用了调用堆栈:

"Thread-2" #15 prio=5 os_prio=0 tid=0x00007fb888023000 nid=0xc0f runnable [0x00007fb8ca696000]
   java.lang.Thread.State: RUNNABLE
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(FileInputStream.java:255)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        - locked <0x00000000ea926290> (a java.lang.UNIXProcess$ProcessPipeInputStream)
        at java.io.FilterInputStream.read(FilterInputStream.java:107)
        at scala.sys.process.BasicIO$.loop$1(BasicIO.scala:234)
        at scala.sys.process.BasicIO$.transferFullyImpl(BasicIO.scala:242)
        at scala.sys.process.BasicIO$.transferFully(BasicIO.scala:223)
        at scala.sys.process.BasicIO$.$anonfun$toStdErr$1(BasicIO.scala:212)
        at scala.sys.process.BasicIO$.$anonfun$toStdErr$1$adapted(BasicIO.scala:212)
        at scala.sys.process.BasicIO$$$Lambda$335/590671716.apply(Unknown Source)
        at scala.sys.process.ProcessBuilderImpl$Simple.$anonfun$run$4(ProcessBuilderImpl.scala:79)
        at scala.sys.process.ProcessBuilderImpl$Simple$$Lambda$345/1512415799.apply$mcV$sp(Unknown Source)
        at scala.sys.process.ProcessImpl$Spawn$$anon$1.run(ProcessImpl.scala:23)

"Thread-1" #14 prio=5 os_prio=0 tid=0x00007fb888021000 nid=0xc0e runnable [0x00007fb8ca797000]
   java.lang.Thread.State: RUNNABLE
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(FileInputStream.java:255)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:284)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
        - locked <0x00000000ea9241d0> (a java.lang.UNIXProcess$ProcessPipeInputStream)
        at java.io.FilterInputStream.read(FilterInputStream.java:107)
        at scala.sys.process.BasicIO$.loop$1(BasicIO.scala:234)
        at scala.sys.process.BasicIO$.transferFullyImpl(BasicIO.scala:242)
        at scala.sys.process.BasicIO$.transferFully(BasicIO.scala:223)
        at scala.sys.process.BasicIO$.$anonfun$toStdOut$1(BasicIO.scala:217)
        at scala.sys.process.BasicIO$.$anonfun$toStdOut$1$adapted(BasicIO.scala:217)
        at scala.sys.process.BasicIO$$$Lambda$334/1481715712.apply(Unknown Source)
        at scala.sys.process.ProcessBuilderImpl$Simple.$anonfun$run$3(ProcessBuilderImpl.scala:76)
        at scala.sys.process.ProcessBuilderImpl$Simple$$Lambda$344/1948323324.apply$mcV$sp(Unknown Source)
        at scala.sys.process.ProcessImpl$Spawn$$anon$1.run(ProcessImpl.scala:23)

"process reaper" #12 daemon prio=10 os_prio=0 tid=0x00007fb88801c800 nid=0xc0b waiting for monitor entry [0x00007fb8ca8d1000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at java.lang.UNIXProcess$ProcessPipeInputStream.processExited(UNIXProcess.java:527)
        - waiting to lock <0x00000000ea9241d0> (a java.lang.UNIXProcess$ProcessPipeInputStream)
        at java.lang.UNIXProcess.lambda$initStreams$3(UNIXProcess.java:298)
        at java.lang.UNIXProcess$$Lambda$342/78086683.run(Unknown Source)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)

"scala-execution-context-global-10" #10 daemon prio=5 os_prio=0 tid=0x00007fb91a3eb000 nid=0xc08 in Object.wait() [0x00007fb8caad2000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000ea938828> (a scala.sys.process.ProcessImpl$Spawn$$anon$1)
        at java.lang.Thread.join(Thread.java:1252)
        - locked <0x00000000ea938828> (a scala.sys.process.ProcessImpl$Spawn$$anon$1)
        at java.lang.Thread.join(Thread.java:1326)
        at scala.sys.process.ProcessImpl$SimpleProcess.$anonfun$exitValue$2(ProcessImpl.scala:241)
        at scala.sys.process.ProcessImpl$SimpleProcess.$anonfun$exitValue$2$adapted(ProcessImpl.scala:241)
        at scala.sys.process.ProcessImpl$SimpleProcess.exitValue(ProcessImpl.scala:241)

这里被锁住了:

override def exitValue() = {
  try p.waitFor()                   // wait for the process to terminate
  finally inputThread.interrupt()   // we interrupt the input thread to notify it that it can terminate
  outputThreads foreach (_.join())  // <=== locked here

  p.exitValue()
}

更多细节:

  • Java 8
  • Scala 2.12
  • CentOS 7

我怎样才能使这样一个简单而基本的任务更可靠? 这是 scala.sys.Process 的错误吗?

【问题讨论】:

    标签: scala process ammonite


    【解决方案1】:

    解决方法是使用 Java API:

    val p = Process(Seq(....)).run()
    val cmp = p.getClass.getDeclaredField("p")
    cmp setAccessible true
    val proc = cmp.get(p).asInstanceOf[java.lang.Process]
    proc.waitFor()
    proc.exitValue()
    

    这样就不再锁定了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-30
      • 1970-01-01
      • 1970-01-01
      • 2020-04-21
      • 2011-10-31
      • 2013-09-09
      • 1970-01-01
      相关资源
      最近更新 更多