gpt4 book ai didi

java - JNI : Does C++ calls Java asynchronous?

转载 作者:搜寻专家 更新时间:2023-10-31 01:36:04 24 4
gpt4 key购买 nike

我正在尝试使用 JNI 从 C++ 代码中调用一些 Java 类。今天我在我的程序中遇到了一个非常奇怪的行为。我怀疑 c++ 代码没有等到 java 端完成它的工作,我不知道为什么。

C++ 代码(在共享对象库中)在它自己的 C++ 线程中运行。它正在使用已经启动并运行的 Java 应用程序的现有 JavaVM。在 Java 应用程序加载 JNI_Onload 中的共享对象库时获取的 VM 和 ClassLoader 的引用。这里我在C++线程中调用了我用JNI创建的java对象的java方法:

env->CallVoidMethod(javaClassObject, javaReceiveMethod, intParam, byteParam, objectParam);
uint32_t applicationSideResponseCode = getResponseCode(objectClass, objectParam, env);
resp.setResponseCode(applicationSideResponseCode);
std::string applicationData = getApplicationData(serviceResultClass, serviceResultObject, env);
resp.setData(applicationData);

Java javaReceiveMethod 正在访问数据库并获取一些存储在 objectParam 中的 applicationData。不幸的是,C++ 代码在 java 类完成其工作之前获取了 applicationData。 applicationData 为 null 且 JNI 崩溃。为什么?我找不到任何 Oracle 文档说明 CallVoidMethod 是异步执行的?

编辑

我验证了java方法没有发生异常。一切似乎都很好,除了在 C++ 尝试访问数据时 Java 仍然很忙。

编辑

我可以确认,如果我调试 Java 应用程序,则会显示两个线程。在主线程上,它正在执行 javaReceiveMethod 和一个正在获取 applicationData 的线程。我怎么解决这个问题?在第二个线程中空闲直到数据可用?

编辑

在我的 C++ 代码中,我正在创建一个我想调用的 java 类的新对象:

jmethodID javaClassConstructor= env->GetMethodID(javaClass, "<init>", "()V");
jobject serviceObject = env->NewObject(javaClass, serviceConstructor);
jobject javaClassObject = env->NewObject(javaClass, javaClassConstructor);

之后,我调用如上所示的代码。经过更多调试后,我可以说该方法是在名为 Thread-2 的线程中调用的(我不知道这是 c++ 线程还是来自 JNI 的新线程)。肯定不是java主线程。然而,该方法的工作被中断。这意味着如果我调试代码,我可以看到很快就会设置数据,但在下一个调试步骤中,将执行 getApplicationData 方法(只有在 c++ 调用它时才会发生)。

编辑我调用的 Java 方法:

public int receive(int methodId, byte[] data, ServiceResult result){
log.info("java enter methodID = " + methodId + ", data= " + data);

long responseCode = SEC_ERR_CODE_SUCCESS;

JavaMessageProto msg;
try {
msg = JavaMessageProto (data);
log.info("principal: " + msg.getPrincipal());
JavaMessage message = new JavaMessage (msg);

if(methodId == GET_LISTS){
//this is shown in console
System.out.println("get lists");
responseCode = getLists(message);
//this point is not reached
log.info("leave");
}
//[... different method calls here...]
if(responseCode != SEC_ERR_CODE_METHOD_NOT_IMPLEMENTED){
//ToDoListMessageProto response = message.getProtoBuf();
JavaMessageProto response = JavaMessageProto.newBuilder()
.setToken(message.getToken())
.setPrincipal(message.getPrincipal()).build();
byte[] res = response.toByteArray();
result.setApplicationData(response.toByteArray());
}
else{
result.setApplicationData("");
}

} catch (InvalidProtocolBufferException e) {
responseCode = SEC_ERR_CODE_DATA_CORRUPTED;
log.severe("Error: Could not parse Client message." + e.getMessage());
}

result.setResponseCode((int)responseCode);
return 0;
}

第二种方法是

public long getLists(JavaMessage message) {
log.info("getLists enter");

String principal = message.getPrincipal();
String token = message.getToken();

if(principal == null || principal.isEmpty()){
return SEC_ERR_CODE_PRINCIPAL_EMPTY;
}
if(token == null || token.isEmpty()){
return SEC_ERR_CODE_NO_AUTHENTICATION;
}

//get user object for authorization
SubjectManager manager = new SubjectManager();
Subject user = manager.getSubject();

user.setPrincipal(principal);
long result = user.isAuthenticated(token);
if(result != SEC_ERR_CODE_SUCCESS){
return result;
}
try {
//fetch all user list names and ids
ToDoListDAO db = new ToDoListDAO();
Connection conn = db.getConnection();
log.info( principal + " is authenticated");
result = db.getLists(conn, message);
//this is printed
log.info( principal + " is authenticated");
conn.close(); //no exception here
message.addId("testentry");
//this not
log.info("Fetched lists finished for " + principal);
} catch (SQLException e) {
log.severe("SQLException:" + e.getMessage());
result = SEC_ERR_CODE_DATABASE_ERROR;
}

return result;
}

最佳答案

CallVoidMethod 同步执行。

也许你在 C++ 方面有异常?你使用 C++ jni 异常检查吗?:

env->CallVoidMethod(javaClassObject, javaReceiveMethod, intParam, byteParam, objectParam);
if(env->ExceptionOccurred()) {
// Print exception caused by CallVoidMethod
env->ExceptionDescribe();
env->ExceptionClear();
}

The C++ code (in a shared object library) is running in it's own C++ thread. It is using a existing JavaVM of a java app that is already up and running.

不清楚您是否已将当前线程附加到虚拟机。确保 env 来自 AttachCurrentThread 调用。你会在这里找到例子:How to obtain JNI interface pointer (JNIEnv *) for asynchronous calls .

关于java - JNI : Does C++ calls Java asynchronous?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36219216/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com