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("\n");
}
});
} 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线程执行完成。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFpODM2MDQ1MTA2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="480" height="800" alt="">
android NDK编程:使用posix多线程与mutex相互排斥同步的更多相关文章
- 三、Android NDK编程预备之Java jni入门创建C/C++共享库
转自: http://www.eoeandroid.com/thread-264971-1-1.html 应网友回复,答应在两天前要出一篇创建C/C++共享库的,但由于清明节假期,跟朋友出去游玩,丢手 ...
- 二、Android NDK编程预备之Java jni入门Hello World
转自: http://www.eoeandroid.com/forum.php?mod=viewthread&tid=264543&fromuid=588695 昨天已经简要介绍了J ...
- 一、Android NDK编程预备之Java jni简介
转自: http://www.eoeandroid.com/thread-264384-1-1.html 游戏开发 视频教程 博客 淘帖 论坛›eoe·Android应用开发区›Androi ...
- Android NDK编程,引入第三方.so库
android自带的编译工具NDK进行编译时(非单纯的调用第三方.so而是进行ndk编程),armeabi以及armeabi-v7a文件夹下的第三方so文件将会被删除,只会产生编译后的so文件,其他的 ...
- (转)Android: NDK编程入门笔记
转自: http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html 为何要用到NDK? 概括来说主要分为以下几种情况: 1. 代 ...
- Android NDK编程浅入深出之--Android.mk
Android.mk Android.mk是一个向Android NDK构建系统描写叙述NDK项目的GUN Makefile片段.它是每个NDK项目的必备组件. 构建系统希望它出如今jni子文 ...
- Android NDK编程
1.首先需要声明native方法: public native String helloWorldNdk(); public native String hello_World_Ndk(); 2.然后 ...
- POSIX多线程
全文共分四部分: POSIX多线程—概述 POSIX多线程—异步编程举例 POSIX多线程—线程基本概念 POSIX多线程—互斥量概述 POSIX多线程—概述 Content 1. ...
- Android NDK学习总结
一.android NDK编程步骤 java文件中声明native方法. android工程根目录新建jni文件夹. 调用javah命令为第一步声明的native方法生成相应的.h头文件. 通过win ...
随机推荐
- Linux命令之dig命令挖出DNS的秘密
=== [初次见面] 我相信使用nslookup的同学一定比使用dig的同学多,所以还是有必要花些时间给大家介绍一下dig的. dig,和nslookup作用有些类似,都是DNS查询工具. dig,其 ...
- linux下c图形化编程之gtk+2.0简单学习
在linux下想做一个图形化的界面,然后自己选择使用gtk+2.0来进行编辑,我的电脑已经安装过gtk+2.0了,所以就在网上找了一个安装方法,结果未测试,大家有安装问题可以说下,一起探讨下. 1.安 ...
- nodeJs 常用模块(一)
url url.parse() querystring querystring.parse( [string] , [分隔符] ) ,解析为js字面量 querystring.stringify() ...
- Java(静态)变量、(静态)代码块、构造方法的执行顺序
Java(静态)变量.(静态)代码块.构造方法的执行顺序 总结 1.父类静态变量和静态代码块(先声明的先执行); 2.子类静态变量和静态代码块(先声明的先执行); 3.父类的变量和代码块(先声明的先执 ...
- (13) go map
1.定义 map 无序, key唯一 (1) (2) (3)定义+赋值 2. map的值时map, 记得要make 3.增删改查 (1)增 改 (2)删除 (3)查 4.遍历 值map 嵌套for, ...
- Python之路【第一篇】:介绍、基本语法、流程控制
一.python 简介 python 特点 Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网 ...
- 【LeetCode】shell
195. Tenth Line 输出file.txt中的第十行 答案: # Read from the file file.txt and output the tenth line to stdou ...
- React Native 系列(七)
前言 本系列是基于React Native版本号0.44.3写的.几乎所有的App都使用了ListView这种组件,这篇文章将学习RN中ListView的平铺样式和分组样式. ListView平铺样式 ...
- BZOJ4551 HEOI2016树
可以用并查集,记忆化搜索,线段树多种方法实现. 我这里写的是依照dfs序建线段树,维护区间最大值. #include<bits/stdc++.h> using namespace std; ...
- 我的OI生涯 第一章
第一章 一入电竞深似海 我叫WZY,是TSYZ的一名学生. 2016年7月10日,我进了一个叫做oi的坑. 那时的我不知道什么叫竞赛,不知道什么叫编程,不知道什么是c++. 就记得前一天我特意去图 ...