プロセス(同期ブロックのJavaと同様に)マルチスレッドJNIクリティカルセクションの基本動作


記事のシリーズ

1.基本動作JNIのJava層は、ネイティブメソッドを作成し、対応する関数を生成するJNI
JNIのJavaのプロパティ基本操作2.動作
するJavaのJNI 3基本操作方法
JNI 4ロードおよびアンロード機能、動的登録および抗の基本動作ローカル登録する方法
のプロセス(同期ブロックのJavaと同様に)マルチスレッドクリティカルセクションのJNI 5.基本的な動作を


序文

ネイティブコードでは、同様の達成するためにJavaのsynchronized機能を。それは一つのスレッドのみが動作することができ、同時に、重要な領域です。

synchronized(obj) {
	//这里就是临界区
}

:達成するための機能
、使用<pthread.h>pthread_create()のスレッドを作成し、
使用「セマフォsemaphore.h」は、sem_wait()和sem_post()ミューテックスが使用または「pthread.hの」;信号を待って送信するためにpthread_mutex_lock()和pthread_mutex_unlock()達成します。

JNIも機能と同様の機能を提供しMonitorEnter(jobject)、そしてMonitorExit(jobject)

jオブジェクトについて:
jni.h中で、知ることができ、JCLASS、JSTRING、jarray、すべての種類の名前が変更JOBJECT jthrowableです。

通常、マルチスレッドオペレーティング共有変数に、このような動作は、同期相互に排他的なの使用を必要とします。


ThreadTest.cppファイルで書かれています。(主にenv->書かれた利便ああ^ _ ^)

#include <jni.h>
#include <pthread.h>   //线程
#include <malloc.h>
#include <unistd.h>
#include <cstdlib> //c stdlib.h
#include <ctime> //c time.h
#include <cstdio> //c stdio.h

#include <android/log.h>
#ifndef LOG_TAG
#define LOG_TAG "stone.stone"
#define slogd(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#endif

struct Args3 {
    JavaVM* vm;
    int tid;
};

void* threadFun3(void* args); //线程函数;声明在前,方便test()使用。

void test(JavaVM *vm) {
	 pthread_t pid;
	 for(int i = 0; i < 10; i++) {
        struct Args3 *args = (Args3 *)(malloc(sizeof(struct Args3)));
        args->vm = vm;
        args->tid = i;

        //像如下这样传递,运行还是会报错的,是因为,指针变量的空间太小
//        struct Args3 args3 = {vm, i};
//        struct Args3* args = &args3;

        pthread_create(&pid, nullptr, threadFun3, args);
    }
}

static int count = 0;
void* threadFun3(void* arg) {
    Args3* args = (struct Args3 *)arg;
    JavaVM* vm = args->vm;

    JNIEnv *env = nullptr;
    int status = vm->GetEnv((void **)(&env), JNI_VERSION_1_6);
    if (status < 0) {
        slogd("stone->get env error. get 不到 env,就需要 attach");
        status = vm->AttachCurrentThread(&env, nullptr);
        if (status < 0) {
            slogd("stone->AttachCurrentThread error");
            return nullptr;
        } else {
            slogd("stone->AttachCurrentThread success");
        }
    }

    env->MonitorEnter(g_ObjCall); //进入监视
    
    int tid = args->tid;
    time_t t = time(nullptr) + count;
    srand(t);//设置随机因子,不同的随机因子,生成的随机数才不同
    sleep(rand() % 3); //随机数 取模,再线程睡眠 0~2秒
    count++;
    slogd("stone->threadFun3. tid=%d, count=%d, time=%ld", tid, count, t);
    
    env->MonitorExit(g_ObjCall); //退出监视
    
    return nullptr;
}


別の主要なCPPファイルで:

#include "ThreadTest.cpp"

extern jobject g_ObjCall;//可以被其它地方使用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
	JNIEnv* env;
    if (JNI_OK != vm->GetEnv(reinterpret_cast<void**> (&env),JNI_VERSION_1_6)) {
        slogd("JNI_OnLoad could not get JNI env");
        return JNI_ERR;
    }
	//jclass clazz = env->FindClass("com/stone/ndk/jni/JniActivity");
	//g_ObjCall = env->NewGlobalRef(env->AllocObject(clazz));
	g_ObjCall = env->NewGlobalRef(env->NewIntArray(1));
	
	test(vm);
	return JNI_VERSION_1_6;
}

本実施形態では、ミューテックス効率的な動作では、その結果が出力され、ほとんどの場合、全体の実行時間よりも大きいが2秒であった。有効でない場合、すなわち、マルチスレッド並列動作、2秒以上の全体的な動作時間です。


問題が発生し、使用上の注意

  1. スレッド関数はつ以上のパラメータは、必要な構造を転送し、そして構造が動的メモリを必要とするポインタが渡されます。場合非動的オープンストレージスペースポインタ変数は不十分であり、崩壊します。
  2. 試験()VMのパラメータであり、書き換えJNI_OnLoad(JavaVM* vm, void* reserved)た場合に得られます
  3. なぜスレッド関数に渡すために必要JavaVM*なパラメータ:
    原因JniEnv*ができないスレッドのシェアは、別のスレッドを取得する子が必要で、それは買収を通じてあるJavaVM*の。
    まずvm->GetEnv()取得する権利場合、それはスレッドが子会社となっていることを意味し、
    そうでない場合は、経由vm->AttachCurrentThread(&env, NULL)子会社スレッド、ENVを取得します
  4. なぜグローバル参照変数g_ObjCallを使用します。
    まず第一に、MonitorEnter(jobject)そしてMonitorExit(jobject)この2つの機能を用いて操作する必要があるjobject変数タイプ。
    スレッド関数でjオブジェクトを作成するには、最初に考えたが、このようなものだったというstatic jobject jobject1 = env->NewIntArray(1);静的参照変数を構築するために、しかし、操作がクラッシュを見つけるだろう、静的変数は、参照を作成するのに十分ではありません。
    グローバル参照変数は、要件を満たすためです。
  5. 私が通じ、スレッド関数内で、試してみましたenv->FindClass("classpath")、そしてを通じてenv->AllocObject(jclass)作成するjobject変数を。
    ランが見つかりenv->FindClass()崩壊したとき。
    子スレッドのenvので、カスタムクラスを直接取得することはできません、クラスのJDKを得ることができます。グローバル参照がさえてjclass作成されjobject、それはまた、崩壊します。
  6. 終了スレッド:
    条件を満たすようにカスタマイズされているとき、あなたはできるpthread_exit()コールという最初の出口モニターノートを終了する前に、スレッドを終了env->MonitorExit()
  7. Javaのスレッドが作成され、考えたことがあり、MonitorEnter(jobject)そしてMonitorExit(jobject)また、相互に排他的で同期するために使用することができますか?試み。

公開された400元の記事 ウォンの賞賛364 ビュー162万+

おすすめ

転載: blog.csdn.net/jjwwmlp456/article/details/89389725