【问题标题】:on android how to execute a c++ function from a worker a thread in the main thread and wait for the execution to complete在android上如何从主线程中的一个线程执行一个c++函数并等待执行完成
【发布时间】:2021-03-15 14:01:36
【问题描述】:

线程 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 个。 非常感谢

【问题讨论】:

  • 不,这是与互斥锁同步。我需要将 lambda 从 c++ 传递到 java 并等待(通过使用信号量)
  • Java 不能调用 lambda 但可以调用 JNI 方法。所以你必须定义一个特定的 C++ 方法,然后用你的普通参数调用 Java,当 Java 完成时,它会调用那个特定的 C++ 方法。看来你已经知道 Mutex/Semaphore,所以我不会写给你。
  • 谢谢,你认为我需要做什么来定义这个接受可变参数并返回可变返回码的特定 c++ 函数?
  • 只需调用(从 Java 中)这个“特定 C++ 方法”,因为您正在调用运行您在此处发布的代码的当前 C++ 方法。类似于“JNIEXPORT JNICALL jint Java_com_your_package_cppMethod(env, clazz, arg1, arg, ....) { ... }”的东西,在这种方法中,您将使用 Mutex/Semaphore 进行线程同步。

标签: android android-ndk


【解决方案1】:

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

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...
  }

【讨论】:

  • 谢谢,但我认为它不能解决问题:(
  • 问题更像是java如何使用不同的参数调用mynativefunc1和mynativefunc2。更准确地说,我使用的是第 3 方库,并且我在某个时候到达了工作线程中的 c++ 代码。从这一点开始,我需要在主线程上执行并使用字符串参数同步 mynativefunc1 并等待它完成并将错误代码返回给第 3 方库。然后第 3 方库希望我使用 val1 和 val2 在主线程 mynativefunc2 上执行,并希望我将结果作为布尔值返回给他。韩国
  • 你对 Thread1 和 Thread2 有什么打算?我的代码将 Thread1 视为 Android MainThread/UiThread(不应被阻塞),将 Thread2 视为并行调用 T1 的辅助线程。如果您只想序列化它们,您可以通过调用第二个“env->CallVoidMethod(method, ...);”将“nonBlockingMethod()”转换为“blockingMethod()”。在另一个之后,这样每个Java“blockingMethod()”都应该在下一个执行之前终止。不知不觉中,每个“blockingMethod()”都应该在其末端调用不同的“fakeCallbackFromJava()”。
  • 我需要阻塞主线程(Ui线程),因为mynativefunc1和mynativefunc2执行UI相关的代码。我不确定您是否真的掌握了我提出问题的确切原因。我写的例子是thread1 = main,thread2是worker。如果我用 CallVoidMethod 调用 nonBlockingMethod,Java 怎么知道要调用什么函数?以及我们如何传递参数。流程是: 1. 我在 C++ 的工作线程 2 中。 2. 我需要在主线程中执行 mynativefunc1("hello") 并等待它返回 1。 3. 我将此错误代码返回给第 3 方库
  • 只需在“(non)BlockingMethod()”中添加一个Argument来选择(在Java中)根据该Argument做什么,这样Java方法可以选择哪个“fakeCallback()”方法在它结束时调用。但是,要在这 2 个 Java 调用之间等待,您只需将 NoBlockingMethod 转换为 BlockingMethod,就像我之前说的那样,但即使在 Java 中,您也必须在“AsyncTask.execute()”之后添加一个 Mutex/Semaphore(我现在正在更改我的答案)跨度>
猜你喜欢
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 2015-02-22
  • 2016-04-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多