我有一个C ++应用程序触发基于Akka Actor的MapReduce系统。这是我通过C ++ JNI包装器类MapReduceBridge
做的,考虑到Akka Actor和C ++应用程序线程需要同步(如下所示),它可以正常工作。问题是,通过这种设计,我不得不让我的C ++ MapReduceBridge
类成为单例并使用静态变量,因为通过RegisterNatives
注册的回调方法是全局的。我的问题是什么是进入类实例范围的最佳方式,因此这个C ++ MapReduceBridge
的多个实例可以共存?
两个Java到C ++的回调实现了以下功能:
我在这里使用RegisterNatives
两个回调(从Java到C ++的函数回调),这是C ++方面:
// allow the C++ MapReduceBridge's application thread to wait for the MapReduce system
static boost::mutex mutex_;
static boost::mutex::scoped_lock lock_(mutex_);
static boost::condition_variable callback_condition_;
// callback notification that installation has completed
JNIEXPORT jobject JNICALL com_sfoam_hpcmom_mapreduce_bridge_BridgeClient_startupCompletedCallback(JNIEnv* env, jobject obj) {
log_info << "callback 'startup completed' received";
callback_condition_.notify_one();
}
// callback notification that MapReduce run has completed
JNIEXPORT jobject JNICALL com_sfoam_hpcmom_mapreduce_bridge_BridgeClient_runCompletedCallback(JNIEnv* env, jobject obj) {
log_info << "callback 'run completed' received";
callback_condition_.notify_one();
}
static const JNINativeMethod kCallbackMethods[] = {
{ "startupCompletedCallback", "()V", (void*)&com_sfoam_hpcmom_mapreduce_bridge_BridgeClient_startupCompletedCallback },
{ "runCompletedCallback" , "()V", (void*)&com_sfoam_hpcmom_mapreduce_bridge_BridgeClient_runCompletedCallback }
};
MapReduceBridge::MapReduceBridge(std::string env_jar_path) {
// ...
// snippet where the callbacks are registered
const int methods_size = sizeof(kCallbackMethods) / sizeof(kCallbackMethods[0]);
env_->RegisterNatives(bridge_class_, kCallbackMethods, methods_size);
// ...
}
void MapReduceBridge::run() {
// get BridgeClient's method run and invoke it
env_->CallObjectMethod(bridge_instance_, bridge_run_);
log_info << "run method launched";
// wait for the callback that 'run' has completed
callback_condition_.wait(lock_);
}
在Java方面:
//---------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public void onReceiveResult(double[] results) {
this.results = results;
runCompletedCallback();
}
遵循此示例,我的目标是让同步变量mutex_
,lock_
和callback_condition_
不是静态的,而是我的MapReduceBridge
C ++类的成员,因此能够有多个MapReduceBridge
实例,即回调应该不是静态执行,而是在我当前MapReduceBridge
实例的范围内执行。
e.g。一种可能的解决方案是在Java中保存指向C ++ this
实例的指针,并在回调期间传递该指针。我怎么能在JNI中做到这一点?
答案 0 :(得分:1)
您可以将Java类中的c / c ++对象的地址(即指针)存储为long。当您将long返回到JNI本机层(作为jlong)时,只需将其强制转换回对象指针。
C ++
// callback notification that MapReduce run has completed
JNIEXPORT jobject JNICALL com_sfoam_hpcmom_mapreduce_bridge_BridgeClient_runCompletedCallback(JNIEnv* env, jobject obj, jlong ptr) {
log_info << "callback 'run completed' received";
MapReduceBridge * ptr = (MapReduceBridge *)ptr;
//Use ptr now to reference your instance variables
//callback_condition_.notify_one();
}
void MapReduceBridge::run() {
// get BridgeClient's method run and invoke it
env_->CallObjectMethod(bridge_instance_, bridge_run_, (long)this );
log_info << "run method launched";
// wait for the callback that 'run' has completed
callback_condition_.wait(lock_);
}
爪哇
public void run(long ptr)
{
this.ptrToMapReduceBridge = ptr;
//do stuff
}
@Override
public void onReceiveResult(double[] results) {
this.results = results;
runCompletedCallback(this.ptrToMapReduceBridge);
}