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 ...
随机推荐
- Mysql中的Btree与Hash索引
B-Tree 索引特征 B-Tree索引可以被用在像=,>,>=,<,<=和BETWEEN这些比较操作符上.而且还可以用于LIKE操作符,只要它的查询条件是一个不以通配符开头的 ...
- properties文件不能输入中文
先把他关掉,然后对message.properties 文件右键--属性(properties), 右边最下面一行text file encoding选择other里面的最后一个utf-8, 再点击a ...
- bzoj 1855 dp + 单调队列优化
思路:很容易写出dp方程,很容易看出能用单调队列优化.. #include<bits/stdc++.h> #define LL long long #define fi first #de ...
- bzoj 1898 矩阵快速幂
思路:因为鱼的周期为2, 3, 4, 所以以12个为周期,我们拿走12步得到的矩阵进行快速幂,余下的再进行一次矩阵乘法. #include<bits/stdc++.h> #define L ...
- VS code配置docker的shell环境
今天尝试了下使用docker来做虚拟机,几番折腾后终于搞定可以用了,但是想着每次都要在命令行敲半天也太恶心了,所以就找了一下可视化的管理工具 首先说下,我的docker主机环境是windows10,用 ...
- dump调试函数
//dump调试函数if (!function_exists('dump')) { /* * dump调试函数 */ function dump($var) { $traces = debug_bac ...
- 那些年遇到的php之坑
1. php指针没有重置 $arr = array( array('aaaaaaaa'), array('bbbbbbb') ); unset($arr[0]); unset($arr[1]); so ...
- Django+Nginx+uwsgi搭建自己的博客(七)
上一篇博客中介绍了Blogs App的部分后端功能的实现,在这篇博客中,将继续为大家介绍Blogs App中前端功能的实现. 首先来看发布博客功能的前端页面.在blogs/templates/blog ...
- TCP/IP——ARP与RARP简记
ARP(Address Resolution Protocol):ARP为IP地址到对应的硬件地址(MAC)之间提供动态映射.这个过程是自动完成的,一般应用程序用户和系统管理员不必要关心. ARP高速 ...
- elasticsearch中ik词库配置远程热加载
1. 修改 IKAnalyzer.cfg.xml 配置文件中的<entry key="remote_ext_dict">http://127.0.0.1/xxx.txt ...