转载地址:http://blog.csdn.net/shaohuazuo/article/details/43149193
博客:http://blog.csdn.net/shaohuazuo/article/details/43149193
转载请注明出处:http://blog.csdn.net/shaohuazuo
1.Android线程介绍.
1.线程的概念:
这个是百度百科里的一段话.
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。
一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,
只拥有一点儿在运行中必不可少的资源, 但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。
就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;
阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。
每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
2.Android进程.
在默认情况下,一个App内的各类别(Activity,BroadcastReceiver,Serverice等)都会在同一个进程中执行,
而且这个进程由主线程负责执行,在Android里.一个app也可以同时运行多个进程,可以在manifest.xml文件中进行声明.
再组件后面添加android:process="name" name是进程的名字.可以随意取名.
3.Android线程.
3.1 在android中为了保持良好的用户体验,Android主线程主用来和用户交互.并产生子线程完成一些幕后工作.
3.2 有些后台用户的处理,比如播放音乐,下载图片,等一些耗时的工作就不能由主线程来完成了.
3.3 解决方法由两个.一个是线程.一个是使用进程.在Android中.我们通常使用线程来解决这样的问题.
也可以使用进程来解决.但是创建一个进程需要的资源和线程比,就和前面说的一样,一个是重量级的,一个是LWP的.
3.4 选定Android多线程解决的问题的话.那么不可避免的就是线程安全.资源的竞争问题,Java层的解决方法
和C层的解决原理是一样的.尽量不要产生竞争问题.如果由,则需要加锁保护.比如,java中的lock,同步,
c中的信号量,互斥锁mutex和读写锁,spinlock等等.
3.5 JNI是如何处理线程资源冲突问题的.请看第二节.
2.JavaVM对象和JNIEvn对象.
1.JavaVM结构体.
在Android环境中.定义两个主要的结构体.JavaVM和JavaEvn,在Java环境中.每个进程里可以诞生许多VM实例.
每个实例会有一个JavaVM结构体实例和他对应.但是在Android环境中.每个进程只能诞生一个VM实例,
所以只有一个JavaVM结构体对实例. 通常在VM加载*.so程序库时,
会先调用JNI_OnLoad()函数,在JNI_OnLoad()函数中会将JavaVM指针对象保存到c层JNI的全局变量中.
JavaVM对象是所有线程共享的.
2.JNIEnv结构体
2.1 JNIEnv对象,当Java线程调用到C层的JNI函数的时候.一定会进入VM,VM会产生一个相应的JNIEnv对象.
这JNIEnv对象和线程是一一对应的关系.
2.2 在调用JNIEnv中的函数时.多个线程调用的JNIEnv中的本地函数都是独立的.
因为VM会为每个线程产生一个JNIEnv对象实体.
2.3 在调用函数的时候如果不方便传递JNIEnv对象,可以先获取JavaVM对象,再使用GetEnv()函数获取JNIEnv对象.
2.4 如果c/c++层自己创建的线程,就必须向VM替它诞生相应的JNIEnv对象.并且回传该对象的指针的值.
3.jclass, jmethodID和jfieldID
3.1 功能
jclass,jmethodID和jfieldID三者都指针.通过这个三个指针,能获取到java中的属性和方法.
3.2 生命周期
这个类被载入的时候,这些指针都是有效的.一直到这个类被卸载为止.
3.3 作用域.
jmethodID和jfieldID可以直接存储在c获取C++的全局变量中.它不需要NewGlobalRef()函数进行转换 .
它们是线程和函数之间共享的对象.
但是jobject的所有子类,必须使用NewGlobalRef()方法转化才能生成一个全局对象的引用.
它们默认情况下时局部的.不能函数共享,和多线程共享.
另外还有两个对象, GetStringUTFChars()和GetBytesArrayElements()函数所回传的数据是不需要
使用NewGlobalRef()转换的.
4.Java线程进入JNI本地函数.
4.1 介绍.
在Android中不管是主线程还是子线程都能通过JNI标准调用c++或者C函数.
同样C函数同样也可以调用到Android主线程和其他线程中的函数.
4.2 Demo流程介绍.
1. ResultValue 存储计算的结果信息的类.
2. ActNative是用来执行计算动作的类.
3. CounterNative它讲ResultValue对象传递给C层,并获取返回的一个数.
4. JNI Module获取ConterNative传递的ResultValue对象之后.获取setValue()方法.
5. JNI Module获取CounterNative对象的number对象.
6. 并把这个值赋值给ResultValue对象.
4.3 类图
4.4 代码
1. Java层代码
MainActivity代码:
- package com.zuoshaohua.threadtest;
-
- import android.os.Bundle;
- import android.app.Activity;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class MainActivity extends Activity implements OnClickListener {
-
- private Button runbtn;
- private Button exitbtn;
- private TextView counterView;
- private CounterNative cn;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- exitbtn = (Button) this.findViewById(R.id.exit);
- runbtn = (Button) this.findViewById(R.id.run);
-
- counterView = (TextView) this.findViewById(R.id.counterView);
-
- exitbtn.setOnClickListener(this);
- runbtn.setOnClickListener(this);
-
- cn = new CounterNativesub1();
-
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
-
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public void onClick(View arg0) {
- int id = arg0.getId();
- switch (id) {
- case R.id.run:
- ActNative.nativeExec();
- counterView.setText(cn.result.getResult() + "");
- break;
- case R.id.exit:
- this.finish();
- break;
- default:
- this.finish();
- break;
- }
- }
-
- }
- package com.zuoshaohua.threadtest;
-
- public class ActNative {
- public static native void nativeExec();
- }
- package com.zuoshaohua.threadtest;
-
- public abstract class CounterNative {
- private int number =10 ;
- public ResultValue result;
- static{
- System.loadLibrary("native");
- }
- public CounterNative()
- {
- number = getNumber();
- result = new ResultValue();
- nativeSetup(result);
- }
- public abstract int getNumber();
- private native void nativeSetup(Object obj);
- }
- package com.zuoshaohua.threadtest;
-
- public class CounterNativesub1 extends CounterNative{
- @Override
- public int getNumber() {
-
- return 13;
- }
- }
-
- package com.zuoshaohua.threadtest;
-
- import android.util.Log;
-
- public class ResultValue {
- private int result;
- private String mThreadName;
-
- public int getResult() {
- return result;
- }
-
- public void setResult(int result) {
-
- this.result = result;
- Thread.currentThread().setName( Thread.currentThread().getName()+"-SetValue");
- mThreadName = Thread.currentThread().getName();
- Log.d("ResultValue",mThreadName);
-
- }
-
-
- }
2. Jni层代码C代码
- #include "act.h"
- #include "native.h"
- #include <android/log.h>
- #include <stdio.h>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- jfieldID number_id;
- jmethodID setv_id;
- jobject counter, result;
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_CounterNative_nativeSetup
- (JNIEnv * env, jobject this, jobject resultThis)
- {
-
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","aaaaaaaaa");
- jclass cnclz = (*env)->GetObjectClass(env,this);
- jclass resclz = (*env)->GetObjectClass(env,resultThis);
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","bbbbbbbb");
- number_id = (*env)->GetFieldID(env, cnclz,"number","I");
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","ccccccccc");
- setv_id = (*env)->GetMethodID(env,resclz,"setResult","(I)V");
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","ddddddddd");
-
- counter = (*env)->NewGlobalRef(env,this);
- result = (*env)->NewGlobalRef(env,resultThis);
- __android_log_print(ANDROID_LOG_INFO,"zshh","eeeeeeeeeee");
- }
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_ActNative_nativeExec
- (JNIEnv *env, jclass this)
- {
-
-
- int i = 0;
- int number = (*env)->GetIntField(env,counter,number_id);
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","number = %d", number);
- for(i = 0 ; i<10; i++)
- {
- number += 10;
- }
-
- __android_log_print(ANDROID_LOG_INFO,"zshh","number = %d", number);
-
- (*env) -> CallVoidMethod(env,result,setv_id,number);
-
-
- }
3. Android.mk
- # Copyright (C) 2009 The Android Open Source Project
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src
- LOCAL_PATH := $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_MODULE := native
- LOCAL_SRC_FILES := native.c
- LOCAL_LDLIBS := -llog
- #LOCAL_SHARED_LIBRARIES :=libc
- include $(BUILD_SHARED_LIBRARY)
4. 例程分析
当Java层的主线程准备执nativeSetup函数时,VM就会产生一个JNIEnv机构体对象.这个对象专属主线程.
接着将这个对象传递给nativeSetup()函数的第一参数. 如果由其他的线程也一样.VM也会替其他线程产生对应的JNIEnv对象.
所以不同的线程进入JNI层c函数时,他们JNIEnv的参数是不同的, 但是同一个线程每次进入本地函数,
他们使用的JNIEnv是同一个.这样我们可以避免多线程之间的线程安全问题.而且可以达成跨函数的数据共享.
作者:左少华
博客:http://blog.csdn.net/shaohuazuo/article/details/43149193
转载请注明出处:http://blog.csdn.net/shaohuazuo
5.JNI本地线程进入Java函数.
1.c中的线程如何进入Java层执行函数调用.
在上面我们都是Java的线程通过JNI调用的C.我们需要看看C中的线程如何进入Java层进行调用.
我们在C中生成一个线程.那么这个线程同样需要VM帮助我们去产生JNIEnv对象.
再Java线程进入C本地函数是,这个对象自动VM自动创建的.那么C本地线程进入Java
则需要向VM进行登记告示VM,VM会为这个C线程创建一个JNIEnv对象,之后这个线程就能进入Java层了.
2 .Demo流程说明
Activity : 用来显示Android线程计算的数据,和人机交互的界面.
PrimeNative: 这个类是用来和C和java沟通的类.
C模块:诞生四个线程计算质数.计算完成之后由注册的到java虚拟机中的线程调用java层的方法将数据显示出来.
有了上面三个类.我们们看看整例子的流程.
第一步.我们再Activity中实例话一个PrimeNative,这个时候会调用static{}静态代码块中的代码.
就会去加载动态库,这个时候就会调用到C模块中JNI_OnLoad()函数,我们需要在这个代码中注册我们的线程到VM中.
第二步.当上面完成之后.Java会执行构造函数中的代码.我们在构造函数中使用调用nativeSetup()函数,主要是为了
C能获取jclass或者jmethodID,jfieldID对象,
第三步.从java传递过来的参数.计算该参数范围内有那些是质数.然后把这些质数从C中返回到Android,然后Android
在进行实现.
第四步.将一个质数返回到Android过程如下,每当线程计算完毕,并且当前计算的是一个质数的话.我们就调用java层的
函数将这个质数显示出来.
3 .类图
*上面是整个程序的框图,我们再看看c模块线程之间程序分析图.*
.c层代码内存线程分析图.
4 .代码
例一: JNI单进程进入Java层调用
我们C程序中只有一个进程,负责计算质数.当计算的数是质数的话,就调用callBack返回该质数显示到UI中.
1.java层代码.
- package com.zuoshaohua.threadtest;
-
- import android.os.Bundle;
- import android.app.Activity;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class MainActivity extends Activity implements OnClickListener {
-
- private Button runbtn;
- private Button exitbtn;
- public static TextView counterView;
- private PrimeNative pn;
- public static MainActivity ref;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ref = this;
- setContentView(R.layout.activity_main);
- exitbtn = (Button) this.findViewById(R.id.exit);
- runbtn = (Button) this.findViewById(R.id.run);
- counterView = (TextView) this.findViewById(R.id.counterView);
- pn = new PrimeNative(10, 100);
- exitbtn.setOnClickListener(this);
- runbtn.setOnClickListener(this);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
-
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public void onClick(View arg0) {
- int id = arg0.getId();
- switch (id) {
- case R.id.run:
- ActNative.exec();
- break;
- case R.id.exit:
- this.finish();
- break;
- default:
- this.finish();
- break;
- }
- }
-
- }
- package com.zuoshaohua.threadtest;
-
- public class ActNative {
- public static native void exec();
- }
- package com.zuoshaohua.threadtest;
-
- import android.os.Handler;
- import android.os.Message;
-
- public class PrimeNative {
- private int start;
- private int end;
-
- private static Handler h;
- private static String thName;
- static {
- System.loadLibrary("prime");
- }
-
- public PrimeNative(int start, int end) {
- this.start = start;
- this.end = end;
- if (start > 0 && start < end) {
- init(start, end);
- }
- h = new Handler() {
- public void handleMessage(Message msg) {
- MainActivity.ref
- .setTitle("value = " + String.valueOf(msg.arg1));
- MainActivity.ref.counterView.append(msg.arg1+", ");
- }
- };
- }
-
- void callBack(int result) {
- Message m = h.obtainMessage(1, result, 3, null);
- thName = Thread.currentThread().getName();
- h.sendMessage(m);
- }
-
- private native void init(int start, int end);
- }
2.JNI代码
-
-
-
-
-
-
- #include"prime.h"
- #include"act.h"
- #include<android/log.h>
- #include<stdio.h>
- JavaVM * jvm;
- jmethodID callbackId;
- jobject obj;
- static int startNum;
- static int endNum;
- static const char *classPathPrime = "com/zuoshaohua/threadtest/PrimeNative";
- static const char *classPathAct = "com/zuoshaohua/threadtest/ActNative";
-
- static JNINativeMethod methodPrime[] = {
- {"init", "(II)V", (void *)Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup}
- };
-
- static JNINativeMethod methodExec[] = {
- {"exec","()V", (void*) Java_com_zuoshaohua_threadtest_ActNative_nativeExec}
- };
-
-
- static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods){
-
- jclass clz = (*env)->FindClass(env,className);
- (*env)->RegisterNatives(env, clz, gMethods, numMethods);
- return JNI_TRUE;
- }
-
- static int registerNatives(JNIEnv* env){
- registerNativeMethods(env, classPathPrime, methodPrime, sizeof(methodPrime) / sizeof(methodPrime[0]));
- registerNativeMethods(env, classPathAct, methodExec, sizeof(methodExec) / sizeof(methodExec[0]));
- return JNI_TRUE;
-
- }
-
- jint JNI_OnLoad(JavaVM* vm, void* reserved){
- JNIEnv *env;
- jvm = vm;
- if ((*jvm)->GetEnv(jvm,(void**) &env, JNI_VERSION_1_4) != JNI_OK)
- return -1;
- if (registerNatives(env) != JNI_TRUE)
- return -1;
- return JNI_VERSION_1_4;
- }
-
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup
- (JNIEnv *env, jobject this, jint start, jint end)
- {
-
-
- __android_log_print(ANDROID_LOG_INFO, "PrimeNative", "start = %d, end =%d\n", start, end);
- startNum = start;
- endNum = end;
-
- jclass clz =(*env)->GetObjectClass(env, this);
-
- callbackId = (*env)->GetMethodID(env,clz,"callBack","(I)V");
-
- obj = (*env)->NewGlobalRef(env,this);
- }
-
- int isPrime(int num)
- {
- int i = 0;
- for(i = 2; i*i <= num; i++)
- {
- if( num%i == 0 ){
- return 0;
- }
- }
- return 1;
- }
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_ActNative_nativeExec
- (JNIEnv * env, jclass clz)
- {
- int i = 0 ;
- for(i =startNum; i<endNum; i++)
- {
- if(isPrime(i))
- {
- __android_log_print(ANDROID_LOG_INFO, "ActNative", "prime = %d", i);
- (*env)->CallVoidMethod(env,obj,callbackId,i);
- }
- }
-
-
- __android_log_print(ANDROID_LOG_INFO, "ActNative", "Java_com_zuoshaohua_threadtest_ActNative_nativeExec");
-
- }
例二: 一个JNI本地线程进入Java执行调用.
需要修改jni层的代码如下:
//arm-Linux-androideabi-g++: error: pthread: No such file or directory
-
-
-
-
-
-
- #include"prime.h"
- #include"act.h"
- #include<android/log.h>
- #include<stdio.h>
- #include<pthread.h>
- JavaVM * jvm;
- jmethodID callbackId;
- jobject obj;
- static pthread_t primeThread;
- static int startNum;
- static int endNum;
- static const char *classPathPrime = "com/zuoshaohua/threadtest/PrimeNative";
- static const char *classPathAct = "com/zuoshaohua/threadtest/ActNative";
- extern void* pthreadPirme( void*);
- static JNINativeMethod methodPrime[] = {
- {"init", "(II)V", (void *)Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup}
- };
-
- static JNINativeMethod methodExec[] = {
- {"exec","()V", (void*) Java_com_zuoshaohua_threadtest_ActNative_nativeExec}
- };
-
-
- static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods){
-
- jclass clz = (*env)->FindClass(env,className);
- (*env)->RegisterNatives(env, clz, gMethods, numMethods);
- return JNI_TRUE;
- }
-
- static int registerNatives(JNIEnv* env){
- registerNativeMethods(env, classPathPrime, methodPrime, sizeof(methodPrime) / sizeof(methodPrime[0]));
- registerNativeMethods(env, classPathAct, methodExec, sizeof(methodExec) / sizeof(methodExec[0]));
- return JNI_TRUE;
-
- }
-
- jint JNI_OnLoad(JavaVM* vm, void* reserved){
- JNIEnv *env;
- jvm = vm;
- if ((*jvm)->GetEnv(jvm,(void**) &env, JNI_VERSION_1_4) != JNI_OK)
- return -1;
- if (registerNatives(env) != JNI_TRUE)
- return -1;
- return JNI_VERSION_1_4;
- }
-
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup
- (JNIEnv *env, jobject this, jint start, jint end)
- {
-
-
- __android_log_print(ANDROID_LOG_INFO, "PrimeNative", "start = %d, end =%d\n", start, end);
- startNum = start;
- endNum = end;
-
- jclass clz =(*env)->GetObjectClass(env, this);
-
- callbackId = (*env)->GetMethodID(env,clz,"callBack","(I)V");
-
- obj = (*env)->NewGlobalRef(env,this);
- }
-
- int isPrime(int num)
- {
- int i = 0;
- for(i = 2; i*i <= num; i++)
- {
-
- if( num%i == 0 ){
- return 0;
- }
- }
- return 1;
- }
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_ActNative_nativeExec
- (JNIEnv * env, jclass clz)
- {
- int i = 0 ;
- #if 0
- for(i =startNum; i<endNum; i++)
- {
- if(isPrime(i))
- {
- __android_log_print(ANDROID_LOG_INFO, "ActNative", "prime = %d", i);
- (*env)->CallVoidMethod(env,obj,callbackId,i);
- }
- }
- #endif
- pthread_create(&primeThread,NULL,pthreadPirme,NULL);
-
-
- __android_log_print(ANDROID_LOG_INFO, "ActNative", "Java_com_zuoshaohua_threadtest_ActNative_nativeExec");
- pthread_join(primeThread, NULL);
- <span style="font-family:Courier New;"> </span>
-
- }
- #if 0
- #include <pthread.h> //包含这个头文件.
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
- void *(*start_routine) (void *), void *arg);
- Compile and link with -pthread.
- 如果您使用的是ubuntu系统,可以使用man pthread_create查看函数的说明.
- 参数一: pthread_t类型的指针,它是一个全局区域的一个变量. 该方法会填充这个结构体.
- 参数二: pthread_attr_t 它用来指定线程的属性.
- 参数三: 他是线程执行的函数.
- 参数四: 它是线程执行函数的参数.
-
-
- 1.先GetEnv方法获取这个env对象.如果已经存在,则不需要执行AttachCurrentThread()了.如果不存在,则需要注册.
-
- #endif
- void* pthreadPirme(void* args){
- int i;
- int status;
- JNIEnv *env;
- jboolean isAttached = JNI_FALSE;
- status = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_4);
- if(status < 0) {
- status = (*jvm)->AttachCurrentThread(jvm,&env, NULL);
- if(status < 0) return NULL;
- isAttached = JNI_TRUE;
- }
-
- <span style="font-family:Courier New;"> </span> for(i =startNum; i<endNum; i++)
- {
- if(isPrime(i))
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "prime = %d", i);
- (*env)->CallVoidMethod(env,obj,callbackId,i);
- }
- }
- if(isAttached) (*jvm)->DetachCurrentThread(jvm);
- return NULL;
- }
6.JNI本地函数的多线程安全.
例三: 多个JNI本地线程进入Java执行调用.
-
-
-
-
-
-
- #include"prime.h"
- #include"act.h"
- #include<android/log.h>
- #include<stdio.h>
- #include<pthread.h>
- #include <stdlib.h>
- #define PROC 4
- JavaVM * jvm;
-
-
- jmethodID callbackId;
-
-
-
-
- jobject syncObj;
-
-
- static int startNum;
- static int endNum;
-
-
-
-
-
- typedef struct item_t
- {
- int num;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- }Item_t;
-
-
- static Item_t * item;
- static int count[PROC];
-
-
-
- static void parent(void);
- static void * child(void *p);
- jboolean prime(int num);
- static int getNum(void);
- static void setNum(int i);
-
- static const char *classPathPrime = "com/zuoshaohua/threadtest/PrimeNative";
- static const char *classPathAct = "com/zuoshaohua/threadtest/ActNative";
-
-
- static JNINativeMethod methodPrime[] = {
- {"init", "(II)V", (void *)Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup}
- };
-
- static JNINativeMethod methodExec[] = {
- {"exec","()V", (void*) Java_com_zuoshaohua_threadtest_ActNative_nativeExec}
- };
-
-
- static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods){
-
- jclass clz = (*env)->FindClass(env,className);
- (*env)->RegisterNatives(env, clz, gMethods, numMethods);
- return JNI_TRUE;
- }
-
- static int registerNatives(JNIEnv* env){
- registerNativeMethods(env, classPathPrime, methodPrime, sizeof(methodPrime) / sizeof(methodPrime[0]));
- registerNativeMethods(env, classPathAct, methodExec, sizeof(methodExec) / sizeof(methodExec[0]));
- return JNI_TRUE;
-
- }
-
- jint JNI_OnLoad(JavaVM* vm, void* reserved){
- JNIEnv *env;
- jvm = vm;
- if ((*jvm)->GetEnv(jvm,(void**) &env, JNI_VERSION_1_4) != JNI_OK)
- return -1;
- if (registerNatives(env) != JNI_TRUE)
- return -1;
- return JNI_VERSION_1_4;
- }
-
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_PrimeNative_nativeSetup
- (JNIEnv *env, jobject this, jint start, jint end)
- {
-
-
- __android_log_print(ANDROID_LOG_INFO, "PrimeNative", "start = %d, end =%d\n", start, end);
- startNum = start;
- endNum = end;
-
- jclass clz =(*env)->GetObjectClass(env, this);
-
- callbackId = (*env)->GetMethodID(env,clz,"callBack","(I)V");
-
- syncObj = (*env)->NewGlobalRef(env,this);
- }
-
-
-
-
-
-
- JNIEXPORT void JNICALL Java_com_zuoshaohua_threadtest_ActNative_nativeExec
- (JNIEnv * env, jclass clz)
- {
- int64_t i;
- int j, ret, flag = 0;
- pthread_t tid[PROC];
-
- item = (Item_t*) malloc(sizeof(Item_t));
- if (item == NULL) {
- exit(1);
- }
- item->num = 0;
- pthread_mutex_init(&item->mutex, NULL);
- pthread_cond_init(&item->cond, NULL);
- <span style="color:#FF0000;">for (i=0;i<PROC;i++) {
-
- count[i] = 0;
- ret = pthread_create(tid+i, NULL, child, (void *)i);
- if (ret != 0) {
- exit(1);
- }
- }</span>
- <span style="background-color: rgb(102, 0, 204);">parent();
- for(i = 0;i<PROC;i++)
- {
- pthread_join(tid[i],NULL);
- }
- pthread_mutex_destroy(&item->mutex);
- pthread_cond_destroy(&item->cond);
- free(item);
- }
-
-
-
- jboolean prime(int num)
- {
- int i = 0;
- for(i = 2;i * i <= num; i++)
- {
- if(num % i == 0)
- {
- return JNI_FALSE;
-
- }
- }
- return JNI_TRUE;
- }
-
-
- static int getNum(void)
- {
- int num;
- num = item->num;
- return num;
- }
-
- static void setNum(int i)
- {
- item->num = i;
- return;
- }
-
-
-
- static void * child(void *p)
- {
- JNIEnv *env;
- int ret ,i;
- int64_t j;
- int status;
- jboolean isAttached = JNI_FALSE;
-
- <span style="background-color: rgb(51, 204, 0);">status = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_4);
- if(status < 0) {
- status = (*jvm)->AttachCurrentThread(jvm,&env, NULL);
- if(status < 0) return NULL;
- isAttached = JNI_TRUE;
- }
- </span>
-
-
-
-
- j = (int64_t)p;
- while(1)
- {
-
- ret = pthread_mutex_lock(&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "pthread_muext_lock error\n");
- exit(1);
- }
- while((i = getNum())==0)
- {
-
-
-
-
- ret = pthread_cond_wait(&item->cond,&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "pthread_muext_lock error\n");
- exit(1);
- }
- }
- if(i == -1)
- {
-
- ret = pthread_mutex_unlock(&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "pthread_mutex_unlock(&item->mutex)\n");
- exit(1);
- }
- break;
- }
-
-
- setNum(0);
- ret = pthread_cond_broadcast(&item->cond);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "pthread_cond_broadcast(&item->cond)");
- exit(1);
- }
- ret = pthread_mutex_unlock(&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "pthread_mutex_unlock(&item->mutex)");
- exit(1);
- }
-
- if(prime(i))
- {
-
-
- <span style="color:#FF0000;">(*env)->MonitorEnter(env,syncObj);
- (*env)->CallVoidMethod(env,syncObj,callbackId,i);
- (*env)->MonitorEnter(env,syncObj);</span>
- }
- count[j]++;
-
- }
-
- __android_log_print(ANDROID_LOG_INFO,"child","pthreadPrime[%d]", count[j]);
-
- <span style="background-color: rgb(0, 153, 0);">if(isAttached) (*jvm)->DetachCurrentThread(jvm);
- pthread_exit((void *)NULL);
- }
-
-
-
-
-
-
- static void parent(void)
- {
- int i,ret,j;
- for(i=startNum;i<endNum;i++)
- {
- while(1)
- {
- ret = pthread_mutex_lock(&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: mutex_lock");
- exit(1);
- }
-
- while((j= getNum()) > 0)
- {
- ret = pthread_cond_wait(&item->cond,&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: cond_wait");
- exit(0);
- }
- }
- if(j==0)
- {
- setNum(i);
- ret = pthread_cond_broadcast(&item->cond);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: brocast");
- exit(0);
- }
-
- ret = pthread_mutex_unlock(&item->mutex);
- if(ret != 0)
- {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: mutex_unlock");
- exit(0);
- }
- break;
- }
-
- }
- }
- while(1)
- {
- pthread_mutex_lock(&item->mutex);
- if (ret != 0) {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: mutex_lock");
- exit(1);
- }
- while ((j = getNum()) > 0) {
- ret = pthread_cond_wait(&item->cond, &item->mutex);
- if (ret != 0) {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent::cond_wait");
- exit(1);
- }
- }
- if (j == 0) {
- setNum(-1);
- ret = pthread_cond_broadcast(&item->cond);
- if (ret != 0) {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: broadcast");
- exit(1);
- }
- ret = pthread_mutex_unlock(&item->mutex);
- if (ret != 0) {
- __android_log_print(ANDROID_LOG_INFO, "pthreadPrime", "parent:: mutex_unlock");
- exit(1);
- }
- break;
- }
- }
- }
3.Android.mk文件
- # Copyright (C) 2009 The Android Open Source Project
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src
- LOCAL_PATH := $(call my-dir)
-
- include $(CLEAR_VARS)
-
- LOCAL_MODULE := prime
- LOCAL_SRC_FILES := prime.c
- LOCAL_LDLIBS := -llog
- LOCAL_SHARED_LIBRARIES := pthread
- include $(BUILD_SHARED_LIBRARY)