NDK--C语言线程运用及jni创建线程

关于linux中线程的知识:https://blog.csdn.net/wucz122140729/article/details/98588567

关于linux中线程同步的知识:https://blog.csdn.net/wucz122140729/article/details/98589012

linux线程是由进程模拟,和进程没有什么本质上的区别,相比于进程,线程在使用上便利很多,线程之间可以共享数据,但这也带来了一系列的问题。在我们在一个线程中对一个数据进行操作时,有时不希望别的线程修改数据,因此锁就诞生了,把资源进行上锁和解锁,被上锁的资源,在别的线程想要访问时,将不能访问,根据逻辑处理,一般情况下会进入阻塞状态(等待),被称为线程同步

线程的锁的种类有互斥锁、读写锁、条件变量、自旋锁、信号灯。实际开发中只需要会玩互斥锁就够了
这边在CentOS中创建一个c文件,其中创建两个线程,分别对一个int变量做处理
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>

int num = 0;

pthread_t pthid;

void * thread_start(void *arg){
  while(1){

     num++;

     usleep(random()%200);
  }
}

void * thread_start1(void *arg){
  while(1){

     printf("num1 = %d\n",num);
     num++;
     usleep(random()%200);
     printf("num2 = %d\n",num);

     usleep(random()%200);
  }
}


int main(){
 
  srand(time(0)); 

  //创建线程1
  pthread_create(&pthid,0,thread_start,(void *)1);

  //创建线程2
  pthread_create(&pthid,0,thread_start1,(void *)2);

  usleep(20000);

}
thread_start中对num进行++操作,thread_start1中打印num,并做++处理后再打印num,结果如下:
我们预想的是num1和num2是连续的,不想让其他线程影响,所以需要用到线程锁,修改后的c文件:
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>

int num = 0;

pthread_t pthid;

pthread_mutex_t foo_mutex;

void * thread_start(void *arg){
  while(1){

     //申请加锁
     pthread_mutex_lock(&foo_mutex); 

     num++;

     //释放锁
     pthread_mutex_unlock(&foo_mutex);

     usleep(random()%200);
  }
}

void * thread_start1(void *arg){
  while(1){

     //申请加锁
     pthread_mutex_lock(&foo_mutex);

     printf("num1 = %d\n",num);
     num++;
     usleep(random()%200);
     printf("num2 = %d\n",num);

     //释放锁
     pthread_mutex_unlock(&foo_mutex);

     usleep(random()%200);
  }
}


int main(){
 
  srand(time(0)); 
 
  //默认锁类型:当一个线程加锁以后,其余请求锁的线程将形成一个等待队列,并在解锁后按优先级获得锁
  pthread_mutex_init(&foo_mutex, NULL);

  //创建线程1
  pthread_create(&pthid,0,thread_start,(void *)1);

  //创建线程2
  pthread_create(&pthid,0,thread_start1,(void *)2);

  usleep(20000);
 
  //销毁锁
  pthread_mutex_destroy(&foo_mutex);
}
执行结果如下:num1和num2是连续的数字

JNI创建线程

在JNI中,我们在java层调用native方法,是在一个线程中的,所以主线程中调用native方法,如果耗时严重,有必要在native层使用多线程,下面介绍native中使用多线程的方法
首先新建一个Java类
package com.aruba.ndkapplication;

import android.util.Log;

/**
 * Created by aruba on 2020/4/17.
 */
public class ThreadUtils {
    public static native void startThread();

    public native void setEnv();

    public static native void destroy();

    public static void getInfoFromC() {
        Log.i("ThreadUtils", "getInfoFromC方法被native层调用");
        destroy();
    }
}
在c++中编写相应的方法,由于一个应用对应一个JVM,一个线程对应一个ENV,所以JNI中使用线程比较特殊,需要通过AttachCurrentThread先将线程添加到JVM,得到对应的ENV,并且子线程中得到的ENV不能使用FindClass方法获取非系统class,通过AttachCurrentThread附加到虚拟机的线程在查找类时只会通过系统类加载器进行查找,不会通过应用类加载器进行查找,因此可以加载系统类,但是不能加载非系统类,如自己在java层定义的类会返回NULL。所以我们这边使用java的setEnv方法调用native层,保存一个全局的jobject
//===================================多线程================================================

#include <pthread.h>

pthread_t pthid;
JavaVM *vm;
jobject g_obj;

//线程方法
void *thread_start(void *arg) {
    LOGI("thread_start begin");
    JNIEnv *env;
    //将线程添加到JVM中
    if (vm->AttachCurrentThread(&env, NULL) != JNI_OK) {
        LOGI("%s AttachCurrentThread error failed ", __FUNCTION__);
        return NULL;
    }

    sleep(3);
    //调用java中的getInfoFromC方法
    jclass clz = env->GetObjectClass(g_obj);
    jmethodID mid = env->GetStaticMethodID(clz, "getInfoFromC", "()V");
    env->CallStaticVoidMethod(clz, mid);
    
    pthread_exit(0);
}

//开启线程
JNIEXPORT void JNICALL
native_startThread(JNIEnv *env, jclass type) {
    LOGI("native_startThread begin");

    //创建线程
    pthread_create(&pthid, 0, thread_start, (void *) 1);
}

//设置环境
JNIEXPORT void JNICALL
native_set_env(JNIEnv *env, jobject jobj) {
    if (vm != NULL)
        vm = NULL;

    env->GetJavaVM(&vm);
    //保持ThreadUtils对象
    g_obj = env->NewGlobalRef(jobj);
}


//销毁资源
JNIEXPORT void JNICALL
native_destroy(JNIEnv *env, jclass type) {
    if (vm != NULL)
        vm = NULL;
    env->DeleteGlobalRef(g_obj);
}

//多线程
static const JNINativeMethod gMethodsThread[] = {
        {
                "startThread", "()V", (void *) native_startThread
        },
        {
                "setEnv",      "()V", (void *) native_set_env
        },
        {
                "destroy",     "()V", (void *) native_destroy
        }
};

//注册多线程Method
static int registerNativesThread(JNIEnv *env) {
    LOGI("registerNatives begin");
    jclass clazz;
    //找到java的类
    clazz = env->FindClass("com/aruba/ndkapplication/ThreadUtils");

    if (clazz == NULL) {
        LOGI("clazz is null");
        return JNI_FALSE;
    }

    if (env->RegisterNatives(clazz, gMethodsThread, NELEM(gMethodsThread)) < 0) {
        LOGI("RegisterNatives error");
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

//===================================多线程end================================================

在java中调用
        Button btn_click3 = findViewById(R.id.btn_click3);
        btn_click3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ThreadUtils threadUtils = new ThreadUtils();
                threadUtils.setEnv();
                threadUtils.startThread();
            }
        });
点击按钮后,我们查看logcat
其中native_startThread begin打印在主线程,另外两个都在子线程
demo地址:https://gitee.com/aruba/NDKApplication.git
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容