什么是本机Thread类函数的JNI流程?

时间:2013-12-21 08:14:43

标签: java c++ c multithreading java-native-interface

我是JNI领域的新手,我的目标是研究java.lang.Thread的本地方法,例如registerNatives和start0(),这样我就可以在操作系统级别了解操作时发生的操作系统操作是什么一个线程是 一)创建 b)中开始

所以我浏览了JNI的各种教程,以便了解基础知识。看起来有4个主要步骤 a)在类中编写本机方法的声明(如Thread.java中的start0()) b)在jdk / bin中使用javah工具生成.h文件 c)将这些生成的.h文件和jdk / include中的其他常见.h文件包含到c / c ++项目环境中 d)编写所需的c ++函数。

如果我错过了一步,请纠正我。

问题 - 1)当我将步骤b)应用到像Thread.java这样的标准java文件时,我在JDK中找不到像Thread.h这样的东西。它的确切位置应该是什么?我在apache harmony http://svn.apache.org/repos/asf/harmony/enhanced/sandbox/bootjvm/bootJVM/jni/src/harmony/generic/0.0/include/java_lang_Thread.h中获得了Thread.h的链接,这与我期望在jdk中存在的文件完全相同。 2)我在jdk \ src \ share \ native \ java中看到一个名为Thread.C的文件,该文件包含我在第1点编写的文件java_lang_Thread.h。 Thread.C文件包含代码

Java_java_lang_Thread_registerNatives(JNIEnv *env, jclass cls)

{     (* env) - > RegisterNatives(env,cls,methods,ARRAY_LENGTH(methods)); } 理想情况下,我希望这个代码在Thread.h中存在,为什么它在Thread.C中有什么意义呢? 3)在openjdk \ hotspot \ src \ share \ vm \ runtime中有一个名为thread.cpp的文件,它包含所有方法定义,现在从Thread.h开始

JNIEXPORT void JNICALL Java_java_lang_Thread_start(JNIEnv *, jobject);

我们如何将它映射到Thread.start,因为我注意到start0()和start()之间的映射。 4)由于我是一名java程序员,可能很难理解Thread.CPP中的c ++代码,有人可以引导我到一个链接,其中可能包含这些方法的理论,如set_stack_base(NULL)等?

1 个答案:

答案 0 :(得分:2)

我没有指向jdk或java线程源的链接。也许如果你提供了一个,我可以解决你的问题。

但是,我从你的问题中收集到的是:“Thread.h如何链接到Thread.cpp?”如果这就是你要问的话,那就这样想吧:

Thread.h只包含一堆声明。类似于Java接口。 Thread.c包含该接口的实现。

至于我对你所问的问题的第二个猜测:“java如何创建本机线程?”。

如果我不得不大肆猜测Java在Windows上创建一个线程,我会说定义是使用WINAPI(仅限Windows)或C ++ stl(可移植)编写的:

假设您有一个java Threading类:

public class Threading {
    static{ System.LoadLibrary("Threading"); }

    private Runnable r = null;
    private native void StartNativeThread(Runnable r);

    public Threading(Runnable r) {
        this.r = r;
    }

    public void start() {
        StartNativeThread(this.r);
    }
}

上面的类在其构造函数中传递了一个runnable。当你调用start时,它调用本机函数“StartNativeThread”,该函数将把runnable作为参数。 在C ++方面,它将创建一个线程,该线程将调用它从java端获得的Runnable.run。

WINAPI-C ++:

//object that will hold all thread information.
struct ThreadParams
{
    JNIEnv* env;
    jobject runnable;
};

//function that the thread will call.
DWORD __stdcall RunnableThreadProc(void* ptr)
{
    ThreadParams* p = reinterpret_cast<ThreadParams*>(ptr); //get our thread info from the parameter.
    JNIEnv* env = p->env; //grab our env.
    jobject runnable = p->runnable; //grab our runnable object.
    delete p; //since we allocated on the heap using new, we must delete from the heap.
    //this is because c++ does not have garbage collection.

    jclass RunnableInterface = env->GetObjectClass(runnable); //get our java runnable interface instance.
    jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V"); //get the run method function pointer.
    env->CallObjectMethod(RunnableInterface, Run); //call RunnableInterface.run();
}

JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
    ThreadParams* ptr = new ThreadParams(); //create an object to store our parameters.
    ptr->env = env;  //store the env parameter.
    ptr->runnable = runnable; //store the runnable object.

    //create a thread that calls "RunnableThreadProc" and passes it "ptr" as a param.
    CreateThread(0, 0, RunnableThreadProc, reinterpret_cast<void*>(ptr), 0, 0); 
}

现在上面的内容看起来非常复杂,但完全诚实,但这就是WINAPI。它是用C语言为Windows编写的API。

如果你有一个C ++ x11编译器,并希望避免使用winapi并使用STL-C ++,这可以在几行中完成。 假设我们有与上面相同的java类,那么我们的函数变为:

JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
    std::thread([&]{
        jclass RunnableInterface = env->GetObjectClass(runnable);
        jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
        env->CallObjectMethod(RunnableInterface, Run);
    }).detach();
}

请注意[&]{....}是Lambda函数。它表示可以在另一个函数或参数内创建的函数。

以上也可以翻译/相当于:

void ThreadProc(JNIEnv* env, jobject runnable)
{
    jclass RunnableInterface = env->GetObjectClass(runnable);
    jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V");
    env->CallObjectMethod(RunnableInterface, Run);
}

JNIEXPORT void JNICALL Java_JNIExample_StartNativeThread(JNIEnv* env, jobject obj, jobject runnable)
{
    std::thread(ThreadProc, env, obj).detach();
}

现在实现停止和暂停等其他功能同样简单。你只需在runnable中的java端执行此操作。或者您可以使用WINAPI的TerminateThreadWaitObject等来在C ++端执行此操作。或者如果您选择使用STL-C ++,那么您将使用std::condition_variable

我希望能解决一些问题。如果您还有其他问题,可以发表评论或制作新主题。由你决定。否则,如果我错过了某些内容或将您的问题解释错误,请澄清一下。


EDIT .. 因此对于实际实现,我们可以看到Thread.c包含jvm.h.因此,我们必须找到jvm.h和jvm.cpp。

快速搜索:

Thread.h:http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c

JVM.h:http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/prims/jvm.h

JVM.cpp:http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/jvm.cpp

如果我们现在从thread.c中搜索任何函数。我们可以在thread.c中看到start0映射到JVM_StartThread,所有其他线程函数映射到JVM_XXXXSomeThreadFunc ...

我们现在必须在JVM.h和JVM.cpp中查找这些JVM_函数。一旦找到,你就可以了解它是如何完成的。