android NDK编程:使用posix多线程与mutex相互排斥同步

MainActivity.java

调用原生方法 posixThreads(int threads, int iterations) 启动线程


package com.apress.threads;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

	private EditText editThreads;
	private EditText editIterations;
	private Button btnStart;
	private TextView tvLog;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		nativeInit();
		editThreads = (EditText) findViewById(R.id.threads_edit);
		editIterations = (EditText) findViewById(R.id.iterations_edit);
		btnStart = (Button) findViewById(R.id.start_button);
		tvLog = (TextView) findViewById(R.id.log_view);

		btnStart.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				int threads = getNumber(editThreads, 0);
				int iterations = getNumber(editIterations, 0);

				if (threads > 0 && iterations > 0) {
					startThreads(threads, iterations);
				}
			}
		});
	}

	private void startThreads(int threads, int iterations) {
		// javaThreads(threads, iterations);//使用java的线程来循环
		posixThreads(threads, iterations);// 使用posix线程
	}

	private void javaThreads(int threads, final int iterations) {
		for (int i = 0; i < threads; i++) {
			final int id = i;
			new Thread() {

				@Override
				public void run() {
					nativeWorker(id, iterations);
					super.run();
				}

			}.start();
		}
	}

	private void onNativeMessage(final String message) {
		runOnUiThread(new Runnable() {

			@Override
			public void run() {
				tvLog.append(message);
				tvLog.append("
");
			}
		});
	}

	private native void posixThreads(int threads, int iterations);

	// 初始化
	private native void nativeInit();

	// 释放内存
	private native void nativeFree();

	// java线程直接调用jni
	private native void nativeWorker(int id, int iterations);

	private static int getNumber(EditText editText, int defaultValue) {

		int value;
		try {
			value = Integer.parseInt(editText.getText().toString());
		} catch (Exception e) {
			value = defaultValue;
		}
		return value;
	}

	@Override
	protected void onDestroy() {
		nativeFree();
		super.onDestroy();
	}

	static {
		System.loadLibrary("Threads");
	}

}


com_apress_threads_MainActivity.h:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_apress_threads_MainActivity */

#ifndef _Included_com_apress_threads_MainActivity
#define _Included_com_apress_threads_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_apress_threads_MainActivity
 * Method:    posixThreads
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_posixThreads
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_apress_threads_MainActivity
 * Method:    nativeInit
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeInit
  (JNIEnv *, jobject);

/*
 * Class:     com_apress_threads_MainActivity
 * Method:    nativeFree
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeFree
  (JNIEnv *, jobject);

/*
 * Class:     com_apress_threads_MainActivity
 * Method:    nativeWorker
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_com_apress_threads_MainActivity_nativeWorker
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif


com_apress_threads_MainActivity.cpp:

在java层调用到原生方法Java_com_apress_threads_MainActivity_posixThreads后。封装參数,调用pthread_create创建线程,使用pthread_join监听线程执行结果并回调到java层

线程指向的函数为void* nativeWorkerThread(void* args),在这个函数里将native线程通过JNI来attach到Java环境里,这样native线程才干够使用JNIEnv。运行完成后要Detach。详细说明可參考http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/invocation.html#attach_current_thread

native线程调用nativeWorker函数输出字符串。通过JNIEnv回调java方法。

在初始化方法中初始化JavaVM* gVm,用来attach到虚拟机中。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

#include "com_apress_threads_MainActivity.h"
#include <android/log.h>

#define LOG_TAG "LOG FROM JNI"

#define LOGW(a)  __android_log_write(ANDROID_LOG_WARN,LOG_TAG,a)

//传递pthread參数用的结构体
struct NativeWorkerArgs {
	jint id;
	jint iterations;
};

//回调java的方法
static jmethodID gOnNativeMessage = NULL;
static JavaVM* gVm = NULL; //虚拟机引用,作为全局变量
static jobject gObj = NULL;
static pthread_mutex_t mutex;

//loadLibrary的时候自己主动调用,在这里获得全局vm引用
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
	gVm = vm;

	LOGW("JNI_OnLoad");
	return JNI_VERSION_1_4;
}

void Java_com_apress_threads_MainActivity_nativeInit(JNIEnv *env, jobject obj) {

	//初始化相互排斥量
	if (0 != pthread_mutex_init(&mutex, NULL)) {
		//异常
		jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
		//抛出
		env->ThrowNew(exceptionClazz, "Unable to init mutex--");
	}

	if (NULL == gObj) {
		gObj = env->NewGlobalRef(obj);
	}

	//初始java回调
	if (NULL == gOnNativeMessage) {
		jclass clazz = env->GetObjectClass(obj);
		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 method--");
		}
	}

}

void Java_com_apress_threads_MainActivity_nativeFree(JNIEnv *env, jobject) {

	//释放全局变量
	if (NULL != gObj) {
		env->DeleteGlobalRef(gObj);
		gObj = NULL;
	}

	//释放相互排斥量
	if (0 != pthread_mutex_destroy(&mutex)) {
		//异常
		jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
		//抛出
		env->ThrowNew(exceptionClazz, "Unable to destroy mutex--");
	}
}

//ndk线程运行的代码
void nativeWorker(JNIEnv *env, jobject obj, jint id, jint iterations) {

	//lock
	if (0 != pthread_mutex_lock(&mutex)) {
		//异常
		jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
		//抛出
		env->ThrowNew(exceptionClazz, "Unable to lock mutex--");
		return;
	}

	for (jint i = 0; i < iterations; i++) {
		char message[26];
		sprintf(message, "Worker %d:Iteration %d", id, i);

		//回调java方法
		jstring messageString = env->NewStringUTF(message);
		env->CallVoidMethod(obj, gOnNativeMessage, messageString);

		if (NULL != env->ExceptionOccurred()) {
			break;
		}
		sleep(1);
	}

	//unlock
	if (0 != pthread_mutex_unlock(&mutex)) {
		//异常
		jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
		//抛出
		env->ThrowNew(exceptionClazz, "Unable to unlock mutex--");

	}
}

void Java_com_apress_threads_MainActivity_nativeWorker(JNIEnv *env, jobject obj,
		jint id, jint iterations) {
	nativeWorker(env, obj, id, iterations);
}

//pthread运行的方法
static void* nativeWorkerThread(void* args) {
	JNIEnv* env = NULL;
	if (0 == gVm->AttachCurrentThread(&env, NULL)) {
		NativeWorkerArgs* nativeWorkerAgrs = (NativeWorkerArgs*) args;

		//
		nativeWorker(env, gObj, nativeWorkerAgrs->id,
				nativeWorkerAgrs->iterations);

		delete nativeWorkerAgrs;

		gVm->DetachCurrentThread();
	}

	return (void*) 1;
}

//java调用的。启动多个线程
void Java_com_apress_threads_MainActivity_posixThreads(JNIEnv *env, jobject obj,
		jint threads, jint iterations) {

	//thread handlers
	pthread_t* handles = new pthread_t[threads];

	//启动线程
	for (jint i = 0; i < threads; i++) {

		//thread arguments
		NativeWorkerArgs* nativeWorkArgs = new NativeWorkerArgs();
		nativeWorkArgs->id = i;
		nativeWorkArgs->iterations = iterations;

		//thread handler
		int result = pthread_create(&handles[i], NULL, nativeWorkerThread,
				(void*) nativeWorkArgs);

		if (result != 0) {
			//异常
			jclass exceptionClazz = env->FindClass(
					"java/lang/RuntimeException");
			//抛出
			env->ThrowNew(exceptionClazz, "Unable to create thread--");
			return;
		}
	}

	//线程运行结果
	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 join thread--");
		} else {
			char message[26];
			sprintf(message, "Worker %d:return %d", i, result);

			jstring messageString = env->NewStringUTF(message);
			env->CallVoidMethod(obj, gOnNativeMessage, messageString);

			if (NULL != env->ExceptionOccurred()) {
				return;
			}
		}
	}

}


这里执行的时候会堵塞界面,直接全部native线程执行完成。

代码下载: http://download.csdn.net/detail/hai836045106/7986143

原文地址:https://www.cnblogs.com/blfshiye/p/5384515.html