私はJNIを使って、C++コードからいくつかのJavaクラスを呼び出そうとしています。今日私は私のプログラマーで非常に奇妙な行動を経験しました。私は、C++コードがJava側で作業を終えるまで待たずに、なぜかわからないと思う。JNI: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がクラッシュします。どうして? CallVoidMethodが非同期で実行されているというOracleの文書は見つかりませんか?
編集
私も例外は、Javaメソッドで発生していないことを確認しました。 C++がデータにアクセスしようとしている間にJavaが依然としてビジーであることを除いて、すべてうまくいくようです。
編集
私はJavaアプリケーションをデバッグする場合は2つのスレッドが示されていることを確認することができます。メインスレッドでは、javaReceiveMethod
を実行しており、1つのスレッドはapplicationData
をフェッチしています。どうすればこの問題を解決できますか?データが利用可能になるまで、2番目のスレッドでアイドル状態になっていますか?上記のように、私はコードを呼び出すその後
jmethodID javaClassConstructor= env->GetMethodID(javaClass, "<init>", "()V");
jobject serviceObject = env->NewObject(javaClass, serviceConstructor);
jobject javaClassObject = env->NewObject(javaClass, javaClassConstructor);
:私は、私が呼び出したいJavaクラスの新しいオブジェクトを作成しています私のC++コードで
編集
。より多くのデバッグの後、私はこのメソッドが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;
}
第2の方法は
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;
}
問題の説明を明確にしてください。最初に "javaReceiveMethod"がC++スレッド上で実行され、それがメインスレッド上で実行されたとしますか? Btwでは、メソッド呼び出しは同期して実行されます。 –
私は自分の答えを更新し、それを明らかに説明するつもりです。しかし、現時点では、JNIが何をしているのか、私は非常に混乱しています。 –
呼び出しているJavaメソッドが表示されていません。 – Michael