zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    百度新闻
    Android平台搭建
    9911微博客
    Python基础语法
    虚拟机上CentOS6.9x86_64系统安装教程
    虚拟机下Linux网络配置
    Win2008 Server配置PHP环境
    Win2008 Server下配置安装IIS
    我的第一篇博文
    WCF学习第一晚:基本知识的了解
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5384515.html
Copyright © 2011-2022 走看看