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">NativeThreadsstring>

<stringname="action_settings">Settingsstring>

<stringname="hello_world">NativeThreadsstring>

<stringname="threads_edit">Thread countstring>

<stringname="iterations_edit">Iteration countstring>

<stringname="btn_start">Start Threadsstring>

resources>

MainActivity.java文件

/**

* 原生线程

*

* @version

*

* @Description:

*

* @author Retacn

*

* @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("\n");

}

});

}

@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

/* 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

#include

#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

//成功返回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

定义启动参数结构体

/*原生线程参数*/

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_VALUE0

#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

初始化信号量

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来查询优先级的最大最小值

你可能感兴趣的:(android_c++ 高级编程NDK学习笔记五)