首页 > 解决方案 > 在android上如何从主线程中的一个线程执行一个c++函数并等待执行完成

问题描述

线程 1 是主线程。我有一个在线程 2 中执行的 c++ 代码(我产生的工作线程)。我想在主线程中执行本机函数并等待结果

printf("I am on thread : %s", getthreadid());
int ret = executeOnMainWait(mynativefunc1("hello"));
printf("ret : %d", ret);
printf("I am on thread : %s", getthreadid());
bool b = executeOnMainWait(mynativefunc2(4, 5));
printf("b : %d", b);

int mynativefunc1(char* param) {
    printf("mynativefunc1 I am on thread : %s", getthreadid());
    if(strcmp(param, "hello")) {
        return 1;
    }
    return 2;
}

bool mynativefunc2(int val1, int val2) {
    printf("mynativefunc2 I am on thread : %s", getthreadid());
    return (val1 + val2) == 5;
 }

所以这段代码应该显示:

I am on thread 2
mynativefunc1 I am on thread 1
ret : 1
I am on thread 2
mynativefunc2 I am on thread 1
b : true

我认为我们需要通过jni进入java世界并使用处理程序并将一些内容发布到主线程然后等待它完成,但问题我不知道如何直接使用自己的参数传递函数指针。这个例子只展示了 2 个原生函数,但实际上我有 20 个。非常感谢

标签: androidandroid-ndk

解决方案


怎么做(有些部分是伪代码):

Java code:
  public native void startSecondThread();
  public native void fakeCallbackFromJava();
  public native void fakeCallbackFromJava2();
  public void blockingMethod(int chooseCallbackMethod, @Nullable Object obj, @Nullable String string) {
    final Object syncObj = new Object();
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
          ...run Java code here in UiThread...
         ...here you can use OBJ and STRING arguments...
            //call callbacks according to Argument
          if (chooseCallbackMethod == 1) fakeCallbackFromJava();
          else if (chooseCallbackMethod == 2) fakeCallbackFromJava2();
          syncObj.notify();
        }
    });
    syncObj.wait();
      //we arrive HERE only after "syncObj.notify()" is called
  }
C++ Thread code:
  void foo() {
    JNIEnv *env;
    jvm->AttachCurrentThread((void **)&env, NULL);
    ..."env" is currently synced object that could be used for Java calls...
    ...all following rows depends of what you want to call in Java...
    jclass class = env->GetObjectClass(...);
    jmethod method = env->GetMethodID(class, "blockingMethod", "ILjava/lang/Object;Ljava/lang/String;");
      //first call
    env->CallVoidMethod(method, 1, null, env->NewStringUTF("hello"));
      //(you will arrive HERE only after "blockingmethod(1,null," hello")" is finished from Java UiThread)
      //second call
    env->CallVoidMethod(method, 2, null, null);
      //finishing second thread
    jvm->DetachCurrentThread();
  }
C++ starting Thread:
  #include <thread>
  JavaVM *jvm;
  JNIEXPORT JNICALL void Java_com_your_package_startSecondThread(JNIEnv* env, jclass clazz) {
    env->GetJavaVM(&jvm);
    std::thread first (foo);
    first.join();
  }
C++ Callback:
  JNIEXPORT JNICALL void Java_com_your_package_fakeCallbackFromJava(JNIEnv* env, jclass clazz) {
    ...code called from Java MainThread/UiThread as CALLBACK for arguments: 1,null,"hello"...
  }
  JNIEXPORT JNICALL void Java_com_your_package_fakeCallbackFromJava2(JNIEnv* env, jclass clazz) {
    ...code called from Java MainThread/UiThread as CALLBACK for arguments: 2,null,null...
  }

推荐阅读