代码之家  ›  专栏  ›  技术社区  ›  vitaut

为什么使用重定向的输入/输出流执行交互进程会导致应用程序停止?

  •  1
  • vitaut  · 技术社区  · 15 年前

    我有一个控制台Java程序 sh -i 在单独的进程中,并在进程的输入/输出流和相应的系统流之间复制数据:

    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    class StreamCopier implements Runnable {
        private InputStream in;
        private OutputStream out;
    
        public StreamCopier(InputStream in, OutputStream out) {
            this.in = in;
            this.out = out;
        }
    
        public void run() {
            try {
                int n = 0;
                byte[] buffer = new byte[4096];
                while (-1 != (n = in.read(buffer))) {
                    out.write(buffer, 0, n);
                    out.flush();
                }
            } catch (IOException e) {
                System.out.println(e);
            }
        }
    }
    
    public class Test {
        public static void main(String[] args)
                throws IOException, InterruptedException {
            Process process = Runtime.getRuntime().exec("sh -i");
            new Thread(new StreamCopier(
                    process.getInputStream(), System.out)).start();
            new Thread(new StreamCopier(
                    process.getErrorStream(), System.err)).start();
            new Thread(new StreamCopier(
                    System.in, process.getOutputStream())).start();
            process.waitFor();
        }
    }
    

    在Linux下运行会导致以下结果:

    $ 
    [1]+  Stopped                 java -cp . Test
    

    有谁能解释一下为什么停止这个应用程序以及如何避免它?

    这与我的 question on copying streams ,但我认为这一特殊问题值得单独关注。

    2 回复  |  直到 8 年前
        1
  •  1
  •   jilles    15 年前

    您可以通过调用 sh -i +m ,这将阻止它接管tty。这意味着 fg bg 命令将不起作用,Ctrl+Z将挂起Java应用程序、shell和从它启动的所有程序。

    如果您仍然需要作业控制,那么应该使用一个伪终端来与shell通信,这将创建一个新的tty供shell使用,但我认为Java不支持这个功能。

        2
  •  1
  •   Ben Jackson    15 年前

    你被SIGTTIN或SIGTTOU拦住了。当这些信号试图对TTY进行IO操作时,它们被发送到后台进程。在这种情况下,“后台”是指“不是终端的控制进程组”。我怀疑你的子地狱正在创建一个新的pgrp并接管你的tty。然后,父程序(java)执行IO(在您的情况下,可能是从TTY读取)并获取SIGTTIN。

    确认这一理论的一个简单方法是用更简单的东西(不是外壳)代替sh,这样就不会试图接管tty。

    推荐文章