如何在JNI中使用線程


好一陣子沒有研究技術了,項目管理占據了我很多時間,今天抽空研究了下JNI下面如何創建線程。
我們知道java層創建線程是很容易的事情,繼承Thread或者實現Runnable接口。
有很多事情我們必須在c++層使用,這個就用到JNI,我們可能會使用網絡,這個時候我們可能開啟線程,最后回調java層的方法。那如何在JNI層使用線程呢?
我們知道pthread_create可以在linux下面創建一個線程,很可惜如果光這樣做是無法在android平台使用的,因為這個線程不歸dalvik管理,使用我們的虛擬機就會死掉。
會報下面的錯誤。

05-07 09:03:25.673: E/dalvikvm(718): JNI ERROR: non-VM thread making JNI calls
那怎么辦呢?

上代碼
JNIEnv* g_env;
jobject g_thiz;
JavaVM *g_jvm;
void* thread_get_str(void * argv) {
(g_jvm)->AttachCurrentThread(&g_env, NULL);
LOGE("log in another thread!!!!!!!!!!");
jclass clazz = (g_env)->GetObjectClass(g_thiz);
jfieldID fid = (g_env)->GetFieldID(clazz, "mInstanceName", "Ljava/lang/String;");
jstring jstr = (jstring)(g_env)->GetObjectField(g_thiz, fid);
LOGE("this message is from other thread of c++ %s", (g_env)->GetStringUTFChars(jstr, NULL));
(g_jvm)->DetachCurrentThread();
}
 
void threadTest(JNIEnv* env, jobject thiz) {
if (g_thiz) {
(g_env)->DeleteGlobalRef(g_thiz);
}
g_thiz = (env)->NewGlobalRef(thiz);
g_env = env;
 
pthread_t thread;
 
pthread_create(&thread, NULL, thread_get_str, NULL);
 
}
看到了么關鍵是(g_jvm)->AttachCurrentThread(&g_env, NULL); 和(g_jvm)->DetachCurrentThread(); 函數,是把當前的線程綁定到jvm上,我們通過全局變量實現了參數的傳遞,當然了,其實我們也可以調用AndroidRuntime::getRuntime來獲得vm但是比較麻煩,因為有些頭文件的配置比較麻煩。至此,我們成功的在c++層使用了線程。

盡管現在中國的工程師還是比較急功近利,總是期望知道是什么,而很少問為什么,但是我覺得一個優秀的工程師應該知道為什么。

首先為什么我們不調用那兩個函數就無法使用線程。我的功力有限,簡單的看了下,我們JNI函數中的,evn其實是當前線程的環境參數,使用當我們創建新的線程就無法使用了,當我們調用AttachCurrentThread就是為當前線程創建一些環境參數。
1,AttachCurrentThread   調用 attachThread
2, JavaVMAttachArgs argsCopy;
    if (args == NULL) {
        /* allow the v1.1 calling convention */
        argsCopy.version = JNI_VERSION_1_2;
        argsCopy.name = NULL;
        argsCopy.group = (jobject) dvmGetMainThreadGroup();
    } else {
        assert(args->version >= JNI_VERSION_1_2);
 
        argsCopy.version = args->version;
        argsCopy.name = args->name;
        if (args->group != NULL) {
            argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
        } else {
            argsCopy.group = (jobject) dvmGetMainThreadGroup();
        }
    }
 
    bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
這里我們copy了當期的環境參數到新的線程中。
然后接下來就創建線程,然后讓線程跑起來。

這里我們留一個疑問,也是我的疑問,我們的linux是如何創建線程的,據我所知,linux內核其實是無法區分進程和線程的,對於內核來說一個進程的線程不過是共享線性地址的多個內核線程。只有庫函數是如何安排的,我確實沒有研究過,使用也無法理解dalvik是如何把虛擬機和c++線程聯系起來的。有知道的朋友希望不吝賜教。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM