多线程 JNI 调用
Posted
技术标签:
【中文标题】多线程 JNI 调用【英文标题】:Multithreaded JNI-Calls 【发布时间】:2014-10-21 11:31:52 【问题描述】:我了解到,每次使用JNIEnv
时,我都必须使用jvm->AttachCurrentThread
将c 线程附加到jvm。这应该和互斥锁非常相似,我在方法的开头用jvm->AttachCurrentThread
锁定它,在最后用jvm->DetachCurrentThread()
解锁它。
所以,现在我有了一个更经常使用JNIEnv
的方法。我必须每次都打电话给AttachCurrentThread
吗?这里有一个代码示例:
std::unique_ptr<IState> JNIGame::createEmptyState()
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
if(!jGame_createEmptyState)
jGame_createEmptyState = env->GetMethodID(jGameC, "createEmptyState", "()Ljni/JNIGames$IJNIState;");
JNIState *state = new JNIState();
//needed?
jvm->AttachCurrentThread((void**)&env, NULL);
state->jStateO = env->CallObjectMethod(jGameO, jGame_createEmptyState);
jvm->DetachCurrentThread();
return std::unique_ptr<IState>(state);
如您所见,我附加了两次线程,因为没有第二次,代码会崩溃。但如果它们像互斥体一样,则只需要第一个。你能帮我吗,为什么我每次都需要它们?是不是像现在的代码一样保存?
【问题讨论】:
如果你想从 Java 调用 C/C++ 代码,你应该考虑使用一些自动工具,比如 SWIG。 我有一个 c++ 框架,必须向 java 添加一个接口,所以新的实现可以在 java 中并使用旧框架。旧框架使用线程,但不允许我在框架内更改任何内容。 这就是 SWIG 的用途。它简化了现有 C 和 C++ 代码的绑定创建以从 Java 中使用。您(大多数情况下)不需要关心低级 JVM JNI 的东西。 swig.org @vz0 还有其他恕我直言更易于使用的工具,例如JavaCPP :) 我需要它。从 C++ 端调用 Java 方法。但是昨天我已经完成了:) 【参考方案1】:不确定您所说的“像互斥锁一样”是什么意思,但文档说:“尝试附加已经附加的线程是无操作的。”
您的示例附加了两次,然后分离了一次。第二次附加无效。
我引用的那句话来自 JNI 文档的“调用 API”一章。 “调用 API”是他们调用的收集方法,您需要从 C 调用 Java(与您用来编写可以 从 Java 调用的本机方法的方法相反。)
有几点值得一提:
启动 JVM 的线程是隐式附加的。该线程成为 JVM 的“主”线程。
只要最后一个非守护线程退出,JVM 就会关闭(无法重新启动)。如果本机线程分离,则视为线程退出。
我的应用程序有一个专用的“主”线程,它启动 JVM,通知其他线程它已启动,然后永远休眠。当我的应用程序的其他本机线程都没有使用它时,休眠的“主”线程使我的 JVM 保持活动状态。
【讨论】:
If a native thread detaches, that is counted as a thread exit.
非常感谢。我删除了所有分离并将所有附加更改为守护程序,它现在按计划运行。
That thread becomes the JVM's "main" thread
。你在这里的“主要”是什么?您的意思是当前线程成为 JVM 内部主线程(被 JVM 用于自己的东西)或者您的意思是它实际上成为 Java 执行的主线程(调用 public static void main
的那个)?谢谢
@AndreLiberty,我很抱歉,但这个答案已经超过六年了。自从我上次接触调用调用 API 的代码以来,已经差不多有那么长的时间了。我不记得我为什么这么说。不过,这听起来像是一个简单的测试:调用一个 Java 程序,其 main()
在创建一个永久存在的新的非守护线程后返回。然后,只需注意启动 JVM 的 C 函数调用是否返回就很简单了。
很抱歉,我没有看帖子日期。并感谢您的回复【参考方案2】:
AttachCurrentThread
允许将您在 JVM 之外创建的线程添加到 Java 虚拟机中。它不打算被称为“每次使用JNIEnv
”,也绝不是“类似于互斥锁”。
进一步,引用the documentation:
尝试附加已附加的线程是无操作的。
如果您的代码崩溃,可能是因为AttachCurrentThread
不是互斥锁这一事实。如果您的方法JNIGame::createEmptyState()
被多个线程调用,则您必须使用真正的互斥锁。
通常,在与虚拟机交互时,您只附加一次线程并使其保持连接更长的时间,而不是在每个方法之后将其分离。
【讨论】:
以上是关于多线程 JNI 调用的主要内容,如果未能解决你的问题,请参考以下文章