【发布时间】:2014-10-27 04:45:14
【问题描述】:
我最近问了一个question,它帮助我了解了 C 程序在 Java 方面的作用。我现在的目标是对两个新的子进程执行类似 C 的 fork,同时跟踪父进程 ID 和子进程 ID。但是,我不确定这是否可行。
在这里,我尝试启动进程 P 并运行两个子进程(我认为它们是 InputStreamReaders isr 和 wasr )。我已经得到了进程 P 的 PID。但是,我卡住的地方是 InputStreamReader 并不是一个真正的进程,所以我无法获得进程 ID。
我会像在另一篇文章中提到的那样,这是一个家庭作业,它提供 C 代码指令但敦促 Java 代码响应。最终目标是能够打印“父进程 ID 的子进程 ID 已开始”和“子进程 ID 已终止”——这就是我跟踪每个人的 ID 很重要的原因。
我找到了另一个post,但我不知道如何适应它。
更新:在另一个 SO 用户的帮助下,我意识到我可能以错误的方式处理问题。这里,父进程是java进程,子进程是native进程。下面更新了代码。
原始代码
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class processesorigin {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec("/bin/ls");
final InputStream is = p.getInputStream();
final InputStream was = p.getInputStream();
Thread t = new Thread(new Runnable() {
public void run() {
InputStreamReader isr = new InputStreamReader(is);
InputStreamReader wasr = new InputStreamReader(was);
int ch;
try {
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
while ((ch = wasr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
p.waitFor();
t.join();
int pid = 0;
if(p.getClass().getName().equals("java.lang.UNIXProcess")) {
try {
Field f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
pid = f.getInt(p);
}
catch (Throwable e) {
}
}
System.out.println("Process " + pid + " terminates.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
更新的代码 使用这些tips 和另一个 SO 用户,我发现了如何捕获 Java 进程 ID。然而,每个进程的开始信号仍然存在问题。不过,这可能是另一个问题。
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import sun.management.VMManagement;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
class processesorigin {
public static void main(String[] args) {
try {
Process p = Runtime.getRuntime().exec("/bin/ls");
Process q = Runtime.getRuntime().exec("/bin/ls");
final InputStream is = p.getInputStream();
final InputStream was = q.getInputStream();
/*get PID of Java process*/
final String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
final String jvmPid = runtimeName.split("@")[0];
int pid = 0;
int qid = 0;
if(p.getClass().getName().equals("java.lang.UNIXProcess")) {
/* get the PID of child processes : native ls command*/
try {
Field f = p.getClass().getDeclaredField("pid");
Field g = q.getClass().getDeclaredField("pid");
f.setAccessible(true);
g.setAccessible(true);
pid = f.getInt(p);
qid = g.getInt(q);
}
catch (Throwable e) {
}
}
final int pidCopy = pid;
final int qidCopy = qid;
Thread t = new Thread(new Runnable() {
public void run() {
InputStreamReader isr = new InputStreamReader(is);
InputStreamReader wasr = new InputStreamReader(was);
int ch;
try {
System.out.print("Child process " + pidCopy + " of Parent process " + jvmPid + " begun.");
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
System.out.print("Child process " + qidCopy + " of Parent process " + jvmPid + " begun.");
while ((ch = wasr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
p.waitFor();
q.waitFor();
t.join();
System.out.println("Child process " + pidCopy + " terminated.");
System.out.println("Child process " + qidCopy + " terminated.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
【问题讨论】:
-
您可以使用 Reader 和 Writer 读写本机进程的 stdout 和 stdin。因此,您可以在 Java 代码中读取“ls”的输出。您可以从进程 p 中获得的 PID,这在您的示例中是通过反射完成的。这当然比我的回答要简单得多。
-
@TorstenRömer 如果我使用 Reader 和 Writer,我能获得 ID 吗?我在获取父进程 P 的 PID 时没有问题。这是为子“进程”(当前是 InputStreamReader)找到一种 ID 的想法。有人告诉我这个 Java 对象没有 ID,因此我的难题是。
-
我想我真的误会了。 InputStreamReader 只是一个对象,实际上没有任何 ID,只是一些伪内存地址,如
java.io.BufferedReader@55f96302,与它正在读取的本机进程无关。 -
我仍然不明白的是,为什么您要在嵌套循环中两次尝试从
/bin/ls读取标准输出? -
这两个
InputStreamReaders 不是子进程,它们都只是从同一个本机(子)进程读取标准输出的读者。其中一个是多余的,你永远不会使用超过一个。
标签: java