JNI(五) pthread子线程操作

pthread.h可以在NDK环境里创建子线程,并对线程能够做出互斥所、等待、销毁等控制。

1. 开启和销毁线程

开启线程

pthread_t pthread;
pthread_create(&pthread, NULL, threadFunc, (void *) "");

pthread_create函数能够创建线程,运行了这个函数线程就会运行起来,执行第三个参数所代表的函数

参数1 pthread_t* pthread 线程句柄

参数2 pthread_attr_t const* 线程的一些属性,一般为NULL

参数3 void* (__start_routine)(void) 线程具体执行的函数

参数4 void* 传给线程的参数

等待线程

如果开启线程只有一个可以不写等待线程完成和返回参数,但是如果有多个线程这个就必须要写,不写的话只会运行第一个线程

int retvalue;
pthread_join(pthread,(void**)&retvalue);
if(retvalue!=0){
    LOGD("thread error occurred");
}

线程执行函数

void* threadFunc(void* arg) {
    LOGD("execute native sub thread");
    // 退出线程,返回结果,这里必须要执行,不然程序会报错
    pthread_exit((void*)2);
    return (void*)0;
}

完整示例

#include "pthread.h"
#include "logger.h"

void* threadFunc(void* arg) {
    char* str = (char*) arg;
    LOGD("execute native sub thread");
    LOGD("params: %s", str);
    // 退出线程,这里必须要现在,不然重新会报错
    pthread_exit((void*)2);
    return (void*)0;
}

extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThread(JNIEnv *env,
                                                         jclass clazz) {
    pthread_t pthread;
    jint ret = pthread_create(&pthread, NULL, threadFunc, (void*) "this is params");
    LOGD("pthread_create ret=%d", ret);
  
    // 等待线程方法执行完成返回结果,注意这里会阻塞后续代码执行
    int retvalue;
    pthread_join(pthread, (void **) &retvalue);
    if (retvalue != 0) {
        LOGD("pthread_join ret=%d", retvalue);
    }
    LOGD("pthread_join end");
}

2. 函数参数传递

单个参数

单个参数直接传递到第四个参数即可。

pthread_create(&pthread, NULL, threadFunc, (void*) "this is params");

函数内接受参数

char* str = (char*) arg;

多个参数

多个参数可以通过结构体传递

struct thread_params {
    std::string param1;
    std::string param2;
};

void *threadFunc2(void *arg) {
    thread_params *str;
    str = (thread_params *) arg;
    LOGD("execute native sub thread");
    LOGD("params: %s", str->param1.c_str());
    LOGD("params: %s", str->param2.c_str());
    // 退出线程,返回结果,这里必须要执行,不然程序会报错
    pthread_exit((void*)2);
    return (void*)0;
}

extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThread(JNIEnv *env,
                                                         jclass clazz) {
    pthread_t pthread;
    thread_params *params = new thread_params;
    params->param1 = "this is params1";
    params->param2 = "this is params2";
    jint ret = pthread_create(&pthread, NULL, threadFunc2, (void *) params);
    LOGD("pthread_create ret=%d", ret);
}

3. 回调到java层

分四步

  • 定义Java接口类

  • 根据java的obj获取jclass。jclass可以理解为java中的class对象。

  • 根据第二步中的jclass和方法名字和方法的签名获取该方法的jmethodID。

  • env调用java实例的方法。

定义Java接口类

// java回调接口 INativeListener.java

public interface INativeListener {
   void onNativeCall(String value);
}

public native void nativeThreadCallBack(INativeListener callBack);

非子线程回调到java方法

extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThreadCallback(JNIEnv *env,
                                                                 jclass clazz, jobject call_back) {

    // 获取java中的对象
    jclass cls = env->GetObjectClass(call_back);
    // 获取回调方法的id
    jmethodID mid = env->GetMethodID(cls, "onNativeCall", "()V");
    // 调用java中的方法
    env->CallVoidMethod(call_back, mid);
}

子线程回调到java方法

主要方法是JavaVM中的AttachCurrentThreadDetachCurrentThread两个方法。

JNI接口指针(JNIEnv)仅在当前线程中有效。如果另一个线程需要访问jvm,它必须首先调用AttachCurrentThread()将自己附加到 JVM并获取JNI接口指针。本机线程在调用DetachCurrentThread()来分离它自己之前一直连接到VM。

调用JavaVM中的AttachCurrentThread和DetachCurrentThread我们需要拿到JavaVM *vm指针。通过**jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)**方法全局变量保存一下vm即可。

JavaVM *gvm;
jobject gCallBackObj;
jmethodID gCallBackMid;

void *threadFunc3(void *arg) {
    thread_params *str;
    str = (thread_params *) arg;
    LOGD("execute native sub thread");
    LOGD("params: %s", str->param1.c_str());
    LOGD("params: %s", str->param2.c_str());

    JNIEnv *env = nullptr;
    // 将当前线程添加到Java虚拟机上,返回一个属于当前线程的JNIEnv指针env
    if (gvm->AttachCurrentThread(&env, nullptr) == 0) {
        jstring jstr = env->NewStringUTF("write success");
        // 回调到java层
        env->CallVoidMethod(gCallBackObj, gCallBackMid, jstr);
        // 删除jni中全局引用
        env->DeleteGlobalRef(gCallBackObj);
        // 从Java虚拟机上分离当前线程
        gvm->DetachCurrentThread();
    }
    // 退出线程,返回结果,这里必须要执行,不然程序会报错
    pthread_exit((void *) 2);
    return (void *) 0;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    gvm = vm;

    JNIEnv *env;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }

    return JNI_VERSION_1_6;
}

extern "C" JNIEXPORT void JNICALL
Java_com_gavinchoo_jni_learning_LearningJni_nativeThreadCallback(JNIEnv *env,
                                                                 jclass clazz, jobject call_back) {

    gCallBackObj = env->NewGlobalRef(call_back);
    jclass cls = env->GetObjectClass(call_back);
    gCallBackMid = env->GetMethodID(cls, "onNativeCall", "(Ljava/lang/String;)V");

    pthread_t pthread;
    thread_params *params = new thread_params;
    params->param1 = "this is params1";
    params->param2 = "this is params2";
    jint ret = pthread_create(&pthread, NULL, threadFunc3, (void *) params);
    LOGD("pthread_create ret=%d", ret);

    // 等待线程方法执行完成返回结果,注意这里会阻塞后续代码执行
    int retvalue;
    pthread_join(pthread, (void **) &retvalue);
    if (retvalue != 0) {
        LOGD("pthread_join ret=%d", retvalue);
    }
    LOGD("pthread_join end");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值