java进程'inputStream卡住了 [英] java Process' inputStream stuck

查看:1196
本文介绍了java进程'inputStream卡住了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的方案:


  1. 进程A生成子进程B并旋转线程以排出B的输出。

  2. 进程B生成守护进程C并排空其输出。

  3. 进程B结束,守护进程仍然存在。

  4. 进程A发现进程B通过process.waitFor()退出。但是,它仍然在阅读进程B的输入流。这是因为B启动了一个守护进程。只有当进程C退出时,输入流才会收到EOF。

  1. process A spawns child process B and spins threads to drain B's outputs.
  2. process B spawns daemon process C and drains its outputs, too.
  3. process B finishes, daemon process still lives.
  4. process A finds out that process B exited via process.waitFor(). However, it's stuck on reading the input streams of process B. It's because B has started a daemon. The input stream receives EOF only when the process C exits.

这只发生在Windows上。我正在使用ProcessBuilder。以下是我提出的解决方案,我希望听到您的反馈,因为我不喜欢这些解决方案:

This only happens on Windows. I'm using the ProcessBuilder. Here're the solutions I came up with and I'd like to hear your feedback as none of the solutions I really like:


  1. I可以使用jna来生成守护进程C.这样我可以创建一个足够分离的进程,并且进程A不会停留在从B中排出流。它可以工作,但我不太热衷于该解决方案,因为它意味着一些本机代码(因为我热衷于消费输入,所以很多)。一些灵感如何通过JNA来实现: http://yajsw.sourceforge.net (但它包含方式更多的东西,而不仅仅是流程开始)。

  2. 在jre7上运行。 Jdk7为ProcessBuilder带来了一些新的好东西,例如inheritIO()的东西,也解决了我的问题。显然,当inheritIO()打开时,我可以简单地关闭守护进程C中的所有流(我无论如何都要这样做,因为它是守护进程)并且解决了这个问题。但是,我需要在jre5 +上运行

  3. 在生成守护进程C之前关闭进程B 中的System.out和System.err。再次,它解决了问题,但我真的需要这些流在进程B中工作,因为我向他们写了有用的东西。不好。我希望通过在B& B之间放置某种自举过程来利用这一特性。但是这并没有解决问题。

  4. 我在linux上没有这个问题所以我只能在linux上运行吗?不,我不能。

  5. 使流程A以非阻塞方式消耗流程B的输出。这有点起作用,但不方便。例如。 inputStream.read()不可中断。我可以使用inputStream.available()但它不区分EOF和零字节可用。因此,如果流程A从不对B的输出EOF感兴趣,那么解决方案才有用。此外,这个解决方案似乎更加CPU密集,通常......感觉很尴尬而且不是真正的防弹。

  6. 在--dry-run模式下运行进程C,它只检查是否它可以开始。它尝试启动,发送欢迎消息并退出。它不再长时间运行,因此不会阻止读取。进程B可以获得足够的信心,可以启动C,并且我们可以使用相对简单的JNA代码来生成分离进程而不消耗其输出(消耗输出会使JNA相关代码变得混乱和重量级)。唯一的问题是我们不再是消费者进程的C输出,但它可以通过使C写入进程B可以使用的众所周知的文件来解决。这个解决方案更像是一个大而丑陋的解决方案,但对我们来说是可行的。无论如何,我们正在尝试解决方案1)。

  1. I can use jna to spawn the daemon process C. This way I can create a process that is 'detached enough' and process A is not stuck on draining the streams from B. It works but I'm not very keen on that solution because it means some native code (and lots of that since I'm keen on consuming the inputs). Some inspiration how to do it via JNA is here: http://yajsw.sourceforge.net (however it contains way more stuff than mere process starting).
  2. Run on jre7. Jdk7 brings some new goodies to the ProcessBuilder, e.g. inheritIO() stuff that also solves my problem. Apparently, when inheritIO() is turned on, I can simply close all streams in the daemon process C (which I do anyway because it'a daemon) and that solves the problem. However, I need to run on jre5+
  3. Close the System.out and System.err in process B before spawning the daemon process C. Again, it solves the problem but I really need those streams to work in process B as I write useful stuff to them. No good. I hoped I could take advantage of this characteristic by placing some kind of a bootstrap process between B & C but that didn't solve the problem.
  4. I don't have that problem on linux so could I only run on linux? No, I can't.
  5. Made the process A drain the outputs of process B in a non-blocking way. This somewhat works but it's not convenient. E.g. inputStream.read() is not interruptible. I could use inputStream.available() but it doesn't distinguish between EOF and zero-bytes-available. So the solution is only good if process A is never interested in B's output EOF. Also, this solution seems to be more CPU intensive and generally... feels awkward and not really bullet proof.
  6. Run process C in a --dry-run mode where it just checks if it can be started. It tries to start, sends welcome message and exits. It's no longer long-running so it will not block reads. Process B can gain enough confidence that C can be started and we can use relatively simple JNA code to spawn detached process without consuming its outputs (it's the consuming of outputs makes the JNA-related code messy and heavyweight). The only problem is that we no longer consumer process' C outputs but it can be solved by making C write to a well known file that process B can consume. This solution is more like a big and ugly workaround but kind of workable for us. Anyways, we are trying the solution 1) at the moment.

我真的很感激任何提示!

I would really appreciate any hints!

推荐答案

我刚遇到同样的问题。我想我有一个问题的解决方法。在进程A中,我在Process.waitFor()之后有以下代码片段,其中outT和errT分别是读取进程B的stdout和stderr的线程:

I just encountered the same problem. I think I have a workaround to the problem. In process A, I have the following code fragment after Process.waitFor(), where outT and errT are the threads to read process B's stdout and stderr, respectively:

try {
  outT.join(1000);
  if (outT.isAlive()) {
    errmsg("stdout reader still alive, interrupting", null);
    outT.interrupt();
  }
} catch (Exception e) {
  errmsg("Exception caught from out stream reader: "+e, e);
}
try {
  errT.join(1000);
  if (errT.isAlive()) {
    errmsg("stderr reader still alive, interrupting", null);
    errT.interrupt();
  }
} catch (Exception e) {
  errmsg("Exception caught from err stream reader: "+e, e);
}
p.destroy();

不确定是否需要p.destroy(),但我一直在尝试各种组合处理问题。

Not sure if p.destroy() is needed, but I have been trying all kinds of combinations to deal with the problem.

无论如何,在outT / errT线程的run()方法中,我有以下内容,其中'pipe'变量是Writer实例我正在捕获子进程的stdout / stderr。 'in'变量是从Process获得的stdout或stderr流:

Anyway, in the run() method of the outT/errT threads, I have the following, where the 'pipe' variable is a Writer instance I am capturing stdout/stderr of the sub-process to. The 'in' variable is the stdout, or stderr, stream obtained from Process:

try {
  r = new BufferedReader(new InputStreamReader(in, enc));
  String line;
  while (true) {
    if (Thread.currentThread().isInterrupted()) {
      errmsg("Text stream reader interrupted", null);
      break;
    }
    if (r.ready()) {
      line = r.readLine();
      if (line == null) {
        break;
      }
      pipe.write(line);
      pipe.write(SystemUtil.EOL);
      if (autoFlush) {
        pipe.flush();
      }
    }
  }
  pipe.flush();

} catch (Throwable t) {
  errmsg("Exception caught: "+t, t);
  try { pipe.flush(); } catch (Exception noop) {}

} finally {
  IOUtil.closeQuietly(in);
  IOUtil.closeQuietly(r);
}

似乎我从未从任何子流程获得EOF指示,甚至在子流程终止之后,因此,上面的所有诡计都会阻止过时的线程和阻塞。

It seems that I never get an EOF indication from any sub-process, even after the sub-process terminates, hence, all the chicanery above to prevent stale threads and blocking.

这篇关于java进程'inputStream卡住了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆