【发布时间】:2021-02-09 15:29:02
【问题描述】:
在 非常 长时间的寻找和一个相关的错误之后,我遇到了这种奇怪的行为:
如果在 Linux 上我运行一个 JNI 方法来执行 select:
JNIEXPORT void JNICALL Java_SelectJNI_select(JNIEnv *env, jobject thisObj) {
// Print the curerent PID
fprintf(stderr, "PID: %d\n", getpid());
// Wait for 30 seconds
struct timeval *timeout = (struct timeval *) calloc(1, sizeof(struct timeval));
timeout->tv_sec = 30;
timeout->tv_usec = 0;
select(0, NULL, NULL, NULL, timeout);
return;
}
然后我使用 strace 运行可执行文件,select 不是使用我打印的 PID 执行的,而是使用孩子的 PID 执行的,原始对象实际上在互斥体上等待(如果我在一个普通的小 C 程序中执行相同的调用)。
说strace -f -o strace_output.txt java SelectJNI 打印:
PID: 46811
然后grep select\( strace_output.txt 将返回:
46812 select(0, NULL, NULL, NULL, {tv_sec=30, tv_usec=0} <unfinished ...>
我的猜测是 JNI 正在分叉,并且在某种程度上用自己的包装版本替换了原始选择,可能是为了保持响应。
我有很多问题,但我更关心的是:
- 我的假设正确吗? JNI 替换我脚下的函数?
- 此行为是否记录在某处?
- 调用实际选择的进程似乎总是第一个子进程。我可以依靠吗?如果没有,我如何找出
select实际运行的位置?
【问题讨论】:
-
您是否确认父级没有立即分叉以设置 JVM 中预期的许多线程?
-
我可能没听懂你的话,但我不认为是这样的:如果父母已经分叉了,那么printf报告的pid和in strace 将是相同的。
-
令我惊讶的是,该进程似乎在 fprintf 之后分叉或委托选择调用 ,即调用 select 时。不过,也许我没听懂你的话。
-
如果我没记错的话,strace 输出中的 46812 是 TID,而不是 PID。而是打印
gettid的结果。 -
@Rick77 跑题了,但你可以用
grep select\(代替strace -f -e select ...
标签: java java-native-interface fork