android_c++ 高级编程NDK学习笔记五

  原生线程

1 示例项目

2 java线程

创建项目NativeThread

添加原生支持android tools--->add Native support

创建用户界面: activity_main.xml文件

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

tools:context=".MainActivity">

<EditText

android:id="@+id/edt_threads"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:focusable="true"

android:hint="@string/threads_edit"

android:inputType="number">

</EditText>

<EditText

android:id="@+id/edt_iterations"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:ems="10"

android:hint="@string/iterations_edit"

android:inputType="number"/>

<Button

android:id="@+id/btn_start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="@string/btn_start"/>

<ScrollView

android:id="@+id/scrollview"

android:layout_width="match_parent"

android:layout_height="wrap_content">

<TextView

android:id="@+id/txt_log"

android:layout_width="match_parent"

android:layout_height="wrap_content"/>

</ScrollView>

</LinearLayout>

字符串资源: string.xml文件

<?xmlversion="1.0"encoding="utf-8"?>

<resources>

<stringname="app_name">NativeThreads</string>

<stringname="action_settings">Settings</string>

<stringname="hello_world">NativeThreads</string>

<stringname="threads_edit">Thread count</string>

<stringname="iterations_edit">Iteration count</string>

<stringname="btn_start">Start Threads</string>

</resources>

MainActivity.java文件

 

/**

 * 原生线程

 *

 * @version

 *

 * @Description:

 *

 * @author <ahref="mailto:zhenhuayue@sina.com">Retacn</a>

 *

 * @since 2014-7-9

 *

 */

public class MainActivity extends Activity {

       /* start button */

       private Buttonbtn_start;

       /* threads edit */

       private EditTextedt_threads;

       /* iterations edit*/

       private EditTextedt_iterations;

       /* log textView */

       private TextViewtxt_log;

 

       @Override

       protected voidonCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity_main);

              // 本地方法 初始化原生代码

              nativeInit();

 

              // 实例化控件

              findView();

       }

 

       /**

        * 实例化控件

        */

       private voidfindView() {

              btn_start =(Button) this.findViewById(R.id.btn_start);

              btn_start.setOnClickListener(newOnClickListener() {

 

                     @Override

                     publicvoid onClick(View v) {

                            intthreads = NativeThreadUtils.getIntNumber(edt_threads.getText().toString(), 0);

                            intiterations = NativeThreadUtils.getIntNumber(edt_iterations.getText().toString(),0);

                            if(threads > 0 && iterations > 0) {

                                   //启动给定个数的线程进行迭代

                                   startThreads(threads,iterations);

                            }

                     }

              });

              edt_threads =(EditText) this.findViewById(R.id.edt_threads);

              edt_iterations= (EditText) this.findViewById(R.id.edt_iterations);

              txt_log =(TextView) this.findViewById(R.id.txt_log);

 

       }

 

       /**

        * 启动给定个数的线程进行迭代

        *

        * @param threads

        *           线程数

        * @param iterations

        *           迭代数

        */

       private voidstartThreads(int threads, final int iterations) {

              javaThreads(threads,iterations);

       }

 

       /**

        * 使用基于 java的线程

        *

        * @param threads

        * @param iterations

        */

       private voidjavaThreads(int threads, final int iterations) {

              // 为每一个worker创建军基于java的线程

              for (int i = 0; i < threads; i++) {

                     finalint id = i;

                     Threadthread = new Thread() {

                            @Override

                            publicvoid run() {

                                   //

                                   nativeWorker(id,iterations);

                            }

                     };

                     thread.start();

              }

       }

 

       /**

        * 原生线程回调

        *

        * @param message

        *           原生消息

        */

       private voidonNativeMessage(final String message) {

              runOnUiThread(newRunnable() {

 

                     @Override

                     publicvoid run() {

                            txt_log.append(message);

                            txt_log.append(" ");

                     }

              });

       }

 

       @Override

       public boolean onCreateOptionsMenu(Menumenu) {

              getMenuInflater().inflate(R.menu.main,menu);

              return true;

       }

 

       @Override

       protected voidonDestroy() {

              // 释放原生资源

              nativeFree();

              super.onDestroy();

       }

 

       // 声明本地方法

       /* 初始化本地方法 */

       private native voidnativeInit();

 

       /* 释放原生资源 */

       private native voidnativeFree();

 

       /**

        * 原生worker

        *

        * @param id

        * @param iterations

        */

       private native voidnativeWorker(int id, int iterations);

 

       /**

        * 加载本地库

        */

       static {

              System.loadLibrary("NativeThreads");

       }

}

生成c++头文件

Projectexplorer--->MainActivity.java--->run--->external tools--->generatec and c++ header file

将会在jni目录下生成cn_yue_nativethreads_MainActivity.h头文件,示例代码如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include<jni.h>

/* Header for class cn_yue_nativethreads_MainActivity */

#ifndef _Included_cn_yue_nativethreads_MainActivity

#define _Included_cn_yue_nativethreads_MainActivity

#ifdef __cplusplus

extern"C" {

#endif

#undef cn_yue_nativethreads_MainActivity_MODE_PRIVATE

#define cn_yue_nativethreads_MainActivity_MODE_PRIVATE0L

#undefcn_yue_nativethreads_MainActivity_MODE_WORLD_READABLE

#definecn_yue_nativethreads_MainActivity_MODE_WORLD_READABLE 1L

#undefcn_yue_nativethreads_MainActivity_MODE_WORLD_WRITEABLE

#definecn_yue_nativethreads_MainActivity_MODE_WORLD_WRITEABLE 2L

#undef cn_yue_nativethreads_MainActivity_MODE_APPEND

#define cn_yue_nativethreads_MainActivity_MODE_APPEND32768L

#undefcn_yue_nativethreads_MainActivity_MODE_MULTI_PROCESS

#definecn_yue_nativethreads_MainActivity_MODE_MULTI_PROCESS 4L

#undefcn_yue_nativethreads_MainActivity_BIND_AUTO_CREATE

#definecn_yue_nativethreads_MainActivity_BIND_AUTO_CREATE 1L

#undefcn_yue_nativethreads_MainActivity_BIND_DEBUG_UNBIND

#define cn_yue_nativethreads_MainActivity_BIND_DEBUG_UNBIND2L

#undefcn_yue_nativethreads_MainActivity_BIND_NOT_FOREGROUND

#definecn_yue_nativethreads_MainActivity_BIND_NOT_FOREGROUND 4L

#undefcn_yue_nativethreads_MainActivity_BIND_ABOVE_CLIENT

#define cn_yue_nativethreads_MainActivity_BIND_ABOVE_CLIENT8L

#undefcn_yue_nativethreads_MainActivity_BIND_ALLOW_OOM_MANAGEMENT

#definecn_yue_nativethreads_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L

#undefcn_yue_nativethreads_MainActivity_BIND_WAIVE_PRIORITY

#define cn_yue_nativethreads_MainActivity_BIND_WAIVE_PRIORITY32L

#undefcn_yue_nativethreads_MainActivity_BIND_IMPORTANT

#definecn_yue_nativethreads_MainActivity_BIND_IMPORTANT 64L

#undefcn_yue_nativethreads_MainActivity_BIND_ADJUST_WITH_ACTIVITY

#define cn_yue_nativethreads_MainActivity_BIND_ADJUST_WITH_ACTIVITY64L

#undefcn_yue_nativethreads_MainActivity_CONTEXT_INCLUDE_CODE

#definecn_yue_nativethreads_MainActivity_CONTEXT_INCLUDE_CODE 1L

#undefcn_yue_nativethreads_MainActivity_CONTEXT_IGNORE_SECURITY

#define cn_yue_nativethreads_MainActivity_CONTEXT_IGNORE_SECURITY2L

#undefcn_yue_nativethreads_MainActivity_CONTEXT_RESTRICTED

#definecn_yue_nativethreads_MainActivity_CONTEXT_RESTRICTED 4L

#undefcn_yue_nativethreads_MainActivity_RESULT_CANCELED

#definecn_yue_nativethreads_MainActivity_RESULT_CANCELED 0L

#undef cn_yue_nativethreads_MainActivity_RESULT_OK

#define cn_yue_nativethreads_MainActivity_RESULT_OK -1L

#undefcn_yue_nativethreads_MainActivity_RESULT_FIRST_USER

#definecn_yue_nativethreads_MainActivity_RESULT_FIRST_USER 1L

#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DISABLE

#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DISABLE 0L

#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DIALER

#define cn_yue_nativethreads_MainActivity_DEFAULT_KEYS_DIALER1L

#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SHORTCUT

#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SHORTCUT 2L

#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL

#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L

#undefcn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL

#definecn_yue_nativethreads_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L

/*

 * 初始化本地方法

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeInit

 * Signature: ()V

 */

JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeInit(

              JNIEnv *, jobject);

/*

 * 释放本地资源

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeFree

 * Signature: ()V

 */

 JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeFree(

              JNIEnv *, jobject);

/*

 * 原生worker

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeWorker

 * Signature: (II)V

 */

 JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeWorker(

              JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus

}

#endif

#endif

实现原生函数

/*

 *cn_yue_nativethreads_MainActivity.cpp

 *

 *  Created on: 2014-7-9

 *      Author: retacn

 *

 */

#include<stdio.h>

#include<unistd.h>

#include"cn_yue_nativethreads_MainActivity.h"

//方法ID能被缓存

staticjmethodID gOnNativeMessage = NULL;

/*

 * 初始化本地方法

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeInit

 * Signature: ()V

 */

void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeInit(JNIEnv * env,

              jobject obj) {

       //如果方法没有被缓存

       if (NULL == gOnNativeMessage) {

              //从对象中取得类

              jclass clazz = env->GetObjectClass(obj);

              //为回调方法id

              gOnNativeMessage=env->GetMethodID(clazz, "onNativeMessage", "(Ljava/lang/String;)V");

              //如果没有找到方法

              if (NULL == gOnNativeMessage) {

                     //获取异常类

                     jclass exceptionClazz = env->FindClass(

                                   "java/lang/RuntimeException");

                     //抛出异常

                     env->ThrowNew(exceptionClazz,"Unable to find methond");

              }

       }

}

/*

 * 释放本地资源

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeFree

 * Signature: ()V

 */

void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeFree(JNIEnv * env,

              jobject obj) {

}

/*

 * 原生worker

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeWorker

 * Signature: (II)V

 */

void JNICALL Java_cn_yue_nativethreads_MainActivity_nativeWorker(JNIEnv * env,

              jobject obj, jint id, jint iterations) {

       //循环给定的迭代次数

       for (jint i = 0; i < iterations; i++) {

              //准备消息

              char message[26];

              sprintf(message, "worker %d: iteration %d", id, i);

              //来自c字符串的消息

              jstring messageString = env->NewStringUTF(message);

              //调用原生消息方法

              env->CallVoidMethod(obj,gOnNativeMessage, messageString);

              //检查是否发和异常

              if (NULL != env->ExceptionOccurred()) {

                     break;

              }

              sleep(1);

       }

}

更新android.mk构建脚本

LOCAL_PATH := $(call my-dir)

include$(CLEAR_VARS)

LOCAL_MODULE    := NativeThreads

LOCAL_SRC_FILES :=cn_yue_nativethreads_MainActivity.cpp

include$(BUILD_SHARED_LIBRARY)

3 posix线程

 在原生代码中使用posix线程,需要添加#include <pthread.h>

//成功返回0

Int pthread_create(pthread_t thread,//用该指针返回新线程的句柄

                                  pthread_attr_tconst* cttr,//新线程属性

                                  void*(*start_routine) (void*),//指向中线程启动程序的指针

                                  void*arg);//

在示例中使用posix线程

A 声明原生方法

       /* 使用原生posix线程 */

       privatenativevoid posixThreads(int threads, int iterations);

B 重新生成头文件

/*

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    posixThreads

 * Signature: (II)V

 */

JNIEXPORT void JNICALL Java_cn_yue_nativethreads_MainActivity_posixThreads

  (JNIEnv *, jobject, jint, jint);

C 更新原生代码

  添加#include<pthread.h>

  定义启动参数结构体

/*原生线程参数*/

structNativeWorkerArgs {

       jintid;

       jintiterations;

};

  全局变量保存java vm和对象实例的全局引用

/*java虚拟机接口指针*/

staticJavaVM* gVm = NULL;

/*对象的全局引用*/

staticjobject gObj = NULL;

...

/**

 * 取得java虚拟机接口指针

 */

jintJNI_OnLoad(JavaVM* vm, void* reserved) {

       //缓存java虚拟机接口批针

       gVm = vm;

       return JNI_VERSION_1_4;

}

voidJava_cn_yue_nativethreads_MainActivity_nativeInit(JNIEnv * env,

              jobject obj) {

       //为对象实例创建一个全局引用

       if (NULL == gObj) {

              //创建全局变量

              gObj =env->NewGlobalRef(obj);

              if (NULL == gObj) {

                     goto exit;

              }

                                  }

...

}

  在freeNative中删除全局引用

//删除全局引用

       if (NULL != gObj) {

              env->DeleteGlobalRef(gObj);

              gObj = NULL;

                                  }

  为原生worker线程添加启动程序

/**

 * 为原生worker添加启动程序

 */

staticvoid* nativeWorkerThread(void* args) {

       JNIEnv* env = NULL;

//将当前线程符加到java虚拟机上

       if (0 == gVm->AttachCurrentThread(&env,NULL)) {

              //取得原生worker线程参数

              NativeWorkerArgs* nativeWorkerArgs = (NativeWorkerArgs*) args;

              //在线程上下文中运行wroker

              Java_cn_yue_nativethreads_MainActivity_nativeWorker(env,gObj,

                            nativeWorkerArgs->id,nativeWorkerArgs->iterations);

              //释放原生线程worker线程参数

              delete nativeWorkerArgs;

              //从java虚拟机中分离当前线程

              gVm->DetachCurrentThread();

       }

       return (void*) 1;

}

  实现posixThread原生方法

/*

 *  posix线程

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    posixThreads

 * Signature: (II)V

 */

voidJava_cn_yue_nativethreads_MainActivity_posixThreads(JNIEnv* env,

              jobject obj, jint threads, jint iterations) {

       //为每一个worker创建一个posix线程

       for (jint i = 0; i < threads; i++) {

              NativeWorkerArgs* nativeWorkerArgs = newNativeWorkerArgs();

              nativeWorkerArgs->id= i;

              nativeWorkerArgs->iterations = iterations;

              pthread_t thread;

              //创建一个新线程

              int result = pthread_create(&thread, NULL, nativeWorkerThread,

                            (void*) nativeWorkerArgs);

              if (0 != result) {

                     //获取异常类

                     jclass exceptionClazz = env->FindClass(

                                   "java/lang/RuntimeException");

                     //抛出异常

                     env->ThrowNew(exceptionClazz,"Unable to createthread!");

              }

       }

}

4 从posix线程返回结果

Java_cn_yue_nativethreads_MainActivity_posixThreads是在线程执行后立即返回,通过pthread_join可以合其在线程结束后返回

//函数原型 成功返回结果为0

intpthread_join(pthread_t thid,//目标线程

void ** ret_val);//指向空指针的指针,从启动程序中取得返回值

更改示例程序

/*

 *  posix线程

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    posixThreads

 * Signature: (II)V

 */

voidJava_cn_yue_nativethreads_MainActivity_posixThreads(JNIEnv* env,

              jobject obj, jint threads, jint iterations) {

       //线程句柄

       pthread_t* handles = newpthread_t(threads);

       //为每一个worker创建一个posix线程

       for (jint i = 0; i < threads; i++) {

              NativeWorkerArgs* nativeWorkerArgs = newNativeWorkerArgs();

              nativeWorkerArgs->id= i;

              nativeWorkerArgs->iterations = iterations;

              pthread_t thread;

              //创建一个新线程

              int result = pthread_create(&handles[i], NULL, nativeWorkerThread,

                            (void*) nativeWorkerArgs);

              if (0 != result) {

                     //获取异常类

                     jclass exceptionClazz = env->FindClass(

                                   "java/lang/RuntimeException");

                     //抛出异常

                     env->ThrowNew(exceptionClazz,"Unable to createthread!");

                     goto exit;

              }

       }

       //等待线程终止

       for (jint i = 0; i < threads; i++) {

              void* result = NULL;

              //连接每个句柄

              if (0 != pthread_join(handles[i], &result)) {

                     //获取异常类

                     jclass exceptionClazz = env->FindClass(

                                   "java/lang/RuntimeException");

                     //抛出异常

                     env->ThrowNew(exceptionClazz,"Unable to jointhread!");

              } else {

                     //准备message

                     char message[26];

                     sprintf(message, "worker %d returned %d", i, result);

                     //

                     jstring messageString = env->NewStringUTF(message);

                     //调用原生消息方法

                     env->CallVoidMethod(obj,gOnNativeMessage, messageString);

                     //检查是否产生异常

                     if (NULL != env->ExceptionOccurred()) {

                            goto exit;

                     }

              }

       }

       exit: return;

}

5 posix线程同步

两种最常用的同步机制:

A 互斥锁(mutexes) pthread_mutex_t展示互斥锁到原生代码

使用互斥锁同步posix线程

初始化互斥锁

intpthread_mutex_init(pthread_mutex_t *mutex,//互斥变量

constpthread_mutexattr_t *attr);//互斥锁定义

如果第二个参数为空,则使用默认属性如下:

#define __PTHREAD_MUTEX_INIT_VALUE           0

#definePTHREAD_MUTEX_INITIALIZER        {__PTHREAD_MUTEX_INIT_VALUE}

如果初始化成功互斥锁处于打开状态 ,返回值为0

锁定互斥锁

intpthread_mutex_lock(pthread_mutex_t *mutex);//参数为互斥锁指针

解锁互斥锁

intpthread_mutex_destroy(pthread_mutex_t *mutex);//参数为互斥锁指针

在示例代码中使用互斥锁

  添加互斥锁到原生代码:

/*互斥锁*/

staticpthread_mutex_tmutex;

  在Java_cn_yue_nativethreads_MainActivity_nativeInit函数中初始化互斥锁

//初始化互斥锁

       if (0 != pthread_mutex_init(&mutex, NULL)) {

              //获取异常类

              jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");

              //抛出异常

              env->ThrowNew(exceptionClazz,"Unable toinitialize mutex!");

              goto exit;

                                  }

在Java_cn_yue_nativethreads_MainActivity_nativeFree函数中销毁互斥锁

//销毁互斥锁

       if (0 != pthread_mutex_destroy(&mutex)) {

              //获取异常类

              jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");

              //抛出异常

              env->ThrowNew(exceptionClazz,"Unable to destorymutex!");

                                  }

Java_cn_yue_nativethreads_MainActivity_nativeWorker函数中使用互斥锁

/*

 * 原生worker

 * Class:     cn_yue_nativethreads_MainActivity

 * Method:    nativeWorker

 * Signature: (II)V

 */

voidJava_cn_yue_nativethreads_MainActivity_nativeWorker(JNIEnv * env,

              jobject obj, jint id, jint iterations) {

       //锁定互斥锁

       if (0 != pthread_mutex_lock(&mutex)) {

              //获取异常类

              jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");

              //抛出异常

              env->ThrowNew(exceptionClazz,"Unable to lock mutex!");

              goto exit;

       }

       //循环给定的迭代次数

       for (jint i = 0; i < iterations; i++) {

              //准备消息

              char message[26];

              sprintf(message, "worker %d: iteration %d", id, i);

              //来自c字符串的消息

              jstring messageString = env->NewStringUTF(message);

              //调用原生消息方法

              env->CallVoidMethod(obj,gOnNativeMessage, messageString);

              //检查是否发和异常

              if (NULL != env->ExceptionOccurred()) {

                     break;

              }

              sleep(1);

       }

       //解锁互斥锁

       if (0 != pthread_mutex_unlock(&mutex)) {

              //获取异常类

              jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");

              //抛出异常

              env->ThrowNew(exceptionClazz,"Unable to unlock mutex!");

       }

       exit: return;

}

运行示例程序,得到锁的线程会先执行,以此类推

B 信号量(semaphores)

使用信号量同步posix线程

添加头文件#include <semaphore.h>

初始化信号量

externintsem_init(sem_t *sem,//信号量变量指针

                                  int pshared,//共享标志

                                  unsignedint value);//初始值

锁定信号量

externintsem_wait(sem_t *);

解锁信号量

externintsem_post(sem_t *);

销毁信号量

externintsem_destroy(sem_t *);

6 posix线程的优先级和调度策略

最常使用的调度策略:

SCHED_FIFO:先进先出,基于线程进入列表的时间进行排序,也可以基于优先级

SCHED_RR:循环轮转,是线程执行时间加以限制的SCHED_FIFO,其目的避免线程独占可用的cpu时间

以上调度策略在sched.h头文件中定义,可以在pthread_create创建线程时,用pthread_attr_t的sched_policy域来定义调度策略

也可以在运行时调用,

intpthread_setschedparam(pthread_t thid,//目标线程指针

int poilcy,//调度策略

structsched_paramconst * param);//参数

posixThread的优先级

在pthread_create创建线程时,用pthread_attr_t的sched_policy域来定义调度优先级,也可以在运行时调用,intpthread_setschedparam函数参数中的param中提供优先级

Sched_get_priority_max和Sched_get_priority_min来查询优先级的最大最小值

原文地址:https://www.cnblogs.com/retacn-yue/p/6194260.html