java线程等待死进程完成

发布于 2025-01-06 10:18:52 字数 3502 浏览 0 评论 0原文

我编写了一个java类来执行多线程任务,每个任务运行一个外部进程。 该进程负责将“.chp”文件转换为“.txt”文件。它是用 C 编写的。

这个过程在某一时刻中断,因为当我在终端中查看“顶部”时它消失了(可能是由于 chp 文件损坏)。问题是我的java线程中的进程没有返回。 “process.waitFor()”似乎会永远持续下去(至少直到我为 ExecutorService 指定的 12 小时)。

我是否做错了什么(没有捕获异常?)? 我尝试在 MyThread 中设置一个 String 类型的类变量,并放置一条错误消息来代替抛出新的 RuntimeException,然后在 main 末尾打印 String,但线程代码没有达到这一点。它仍然卡在 waitFor() 处。

一旦C程序失败,进程不应该终止吗?

程序在终端上打印 (cf: MyThread):

A
B
C

main:

String pathToBin = "/path/to/bin";
List<MyThread> threadList = new ArrayList<MyThread>();

for (File f : folderList) {
    File[] chpFilesInFolder = f.listFiles(new FilenameFilter() {

        @Override
        public boolean accept(File dir, String name) {
            if (name.endsWith(".chp")){
                 return true;
            }else{
                 return false;
            }
        }
    });
    File chpFile = writeChpFiles(chpFilesInFolder);
    String[] cmd = {pathToBin, "--arg1", chpFile, "--out-dir", outputFolder};
    MyThread t = new MyThread(cmd, f, chpFilesInFolder);
    threadList.add(t);
}

ExecutorService threadExecutor = Executors.newFixedThreadPool(4);
for(MyThread th : threadList){
    threadExecutor.execute(th);
}
threadExecutor.shutdown();

try {
    threadExecutor.awaitTermination(12, TimeUnit.HOURS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

MyThread:

class MyThread extends Thread{
    private String[] cmd;
    private File chpFolder;
    private File[] chpFilesInFolder;

    public MyThread(String[] cmd, File chpFolder, File[] chpFilesInFolder){
        this.cmd = cmd;
        this.chpFolder = chpFolder;
        this.chpFilesInFolder = chpFilesInFolder;
    }

    @Override
    public void run() {
        Process process = null;
        try{
            System.err.println("A ");
            ProcessBuilder procBuilder = new ProcessBuilder(cmd);
            procBuilder.redirectErrorStream(true);

            System.err.println("B");
            process = procBuilder.start();

            System.err.println("C");
            process.waitFor();

            System.err.println("D");
            if(process.exitValue()!=0) System.err.println("ERROR !"+process.exitValue());

            System.err.println("E");
        }catch(IOException e){
            e.printStackTrace();
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch(Throwable e){
            e.printStackTrace();
        }finally{
            System.err.println("F");
            if(process!=null) {try { process.destroy();} catch(Exception err) {err.printStackTrace();}}
        }

        File[] txtFilesInFolder = chpFolder.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                if (name.endsWith(".chp.txt")){
                    return true;
                }else{
                    return false;
                }
            }
        });

        if (txtFilesInFolder.length==chpFilesInFolder.length){
            for (File chp : chpFilesInFolder) {
                chp.delete();
            }
            File logFile = new File(chpFolder, "apt-chp-to-txt.log");
               if (logFile.exists()){
                   logFile.delete();
               }
        }else{
            throw new RuntimeException("CHPs have not all been transformed to TXT in "+chpFolder.getAbsolutePath());
        }

I wrote a java class in order to perform multithreaded tasks, each task running an external process.
The process is in charge of converting ".chp" files into ".txt" files. It is written in C.

This process breaks at one point because it disappears when looking at a "top" in my terminal (probably due to a corrupted chp file). The problem is that the process in my java thread does not return. The "process.waitFor()" seems to go on forever (at least 'til the 12 hours I specified for the ExecutorService.

Am I doing something wrong (not catching an exception?)?
I tried setting a class variable of type String in MyThread and putting an error message in place of throwing a new RuntimeException, then print the String at the end of the main, but the thread code doesn't reach to this point. It still gets stuck at the waitFor().

Shouldn't the process terminate once the C program has failed?

The program prints on the terminal (cf: MyThread):

A
B
C

main:

String pathToBin = "/path/to/bin";
List<MyThread> threadList = new ArrayList<MyThread>();

for (File f : folderList) {
    File[] chpFilesInFolder = f.listFiles(new FilenameFilter() {

        @Override
        public boolean accept(File dir, String name) {
            if (name.endsWith(".chp")){
                 return true;
            }else{
                 return false;
            }
        }
    });
    File chpFile = writeChpFiles(chpFilesInFolder);
    String[] cmd = {pathToBin, "--arg1", chpFile, "--out-dir", outputFolder};
    MyThread t = new MyThread(cmd, f, chpFilesInFolder);
    threadList.add(t);
}

ExecutorService threadExecutor = Executors.newFixedThreadPool(4);
for(MyThread th : threadList){
    threadExecutor.execute(th);
}
threadExecutor.shutdown();

try {
    threadExecutor.awaitTermination(12, TimeUnit.HOURS);
} catch (InterruptedException e) {
    e.printStackTrace();
}

MyThread:

class MyThread extends Thread{
    private String[] cmd;
    private File chpFolder;
    private File[] chpFilesInFolder;

    public MyThread(String[] cmd, File chpFolder, File[] chpFilesInFolder){
        this.cmd = cmd;
        this.chpFolder = chpFolder;
        this.chpFilesInFolder = chpFilesInFolder;
    }

    @Override
    public void run() {
        Process process = null;
        try{
            System.err.println("A ");
            ProcessBuilder procBuilder = new ProcessBuilder(cmd);
            procBuilder.redirectErrorStream(true);

            System.err.println("B");
            process = procBuilder.start();

            System.err.println("C");
            process.waitFor();

            System.err.println("D");
            if(process.exitValue()!=0) System.err.println("ERROR !"+process.exitValue());

            System.err.println("E");
        }catch(IOException e){
            e.printStackTrace();
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch(Throwable e){
            e.printStackTrace();
        }finally{
            System.err.println("F");
            if(process!=null) {try { process.destroy();} catch(Exception err) {err.printStackTrace();}}
        }

        File[] txtFilesInFolder = chpFolder.listFiles(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                if (name.endsWith(".chp.txt")){
                    return true;
                }else{
                    return false;
                }
            }
        });

        if (txtFilesInFolder.length==chpFilesInFolder.length){
            for (File chp : chpFilesInFolder) {
                chp.delete();
            }
            File logFile = new File(chpFolder, "apt-chp-to-txt.log");
               if (logFile.exists()){
                   logFile.delete();
               }
        }else{
            throw new RuntimeException("CHPs have not all been transformed to TXT in "+chpFolder.getAbsolutePath());
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

风筝在阴天搁浅。 2025-01-13 10:18:52

您的 C 程序是否有可能在 stdout 上生成输出?如果是这样,您需要在 Process.waitFor() 返回之前读取 Process.getOutputStream() - 请参阅 https://bugs.java.com/bugdatabase/view_bug?bug_id=4254231

或者,将您的 C 程序调用为重定向 stdout 的 shell 脚本。

您可以使用 jstack 命令来确认线程确实被阻塞在 Process.waitFor() 处。

Is it possible that your C program is producing output on stdout? If so, you need to read Process.getOutputStream() before Process.waitFor() returns - see https://bugs.java.com/bugdatabase/view_bug?bug_id=4254231

Alternatively, call your C program that a shell script that redirects stdout.

You can use the jstack command to confirm that the thread is indeed blocked at Process.waitFor().

花间憩 2025-01-13 10:18:52

您可以让主线程等待合理的时间,然后调用 MyThread 类上的某些方法来终止已启动的进程,从而导致线程完成。

You could have the main thread wait for a reasonable amount of time and then call some method on the MyThread class to kill the started process, thus causing the thread to finish.

傾旎 2025-01-13 10:18:52

我经常建议在使用消息传递解决方案使 C 程序与 Java 应用程序交互时使用更健壮和专业的观点,这样可以轻松干净地避免那些非守护线程因崩溃而永远等待您的 C 应用程序...现在所有代理都有一个 STOMP 接口,对于任何类型的应用程序调用来说都非常酷(只需使用任何 Http 库),代理配置将能够重新启动未完成的作业,设置一些超时等等..即使JMS不支持请求并响应它很容易实现这样的范例......

HTH
杰罗姆

as often I would suggest to use a more robust and professional point of view while using a messsaging solution to make your C program interact with your Java application, it will be easy and clean to avoid those non daemon threads waiting for ever because of the crash of your C application... now all brokers have a STOMP interface which is pretty cool for any kind of application to invoke (just use any Http library), broker configuration will enable to restart non finished jobs, to put some timeouts and so one..Even if JMS does not support request and response it's quite easy to implement such paradigm....

HTH
Jerome

洒一地阳光 2025-01-13 10:18:52

如果我理解正确的话,你的 Java 线程在 C 程序崩溃后仍然在等待。

使生成的 C 进程发送心跳。您甚至可以通过将某些内容打印到控制台(或插入表中)并每隔一段时间唤醒 Java 线程并检查心跳来完成此操作。如果不存在,则假设 C 进程已死亡并终止该线程。

If I understad correctly, your Java threads remain waiting after the C program crashes.

Make the spawned C process send heart beats. You can do this even by printing sth to console (or inserting in a table) and have the Java thread every so often wake up and check the heartbeat. If it's not there, assume the C process died and terminate the thread.

请别遗忘我 2025-01-13 10:18:52

在 Java 中启动外部进程可能会有点棘手。我通常会尝试避免它们,因为您将不得不处理不同的错误代码和一些终端疯狂。我建议您使用专门的库,例如 commons-exec (http://commons.apache.org/exec/)

Launching external processes in Java can get a little bit tricky. I usually try to avoid them as you'll have to deal with different error codes and some terminal madness. I recommend you use specialized libraries such as commons-exec (http://commons.apache.org/exec/)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文