我们知道taskset命令可以将进程绑定到某个或某几个cpu上执行。(不知道的google哦)
在某些情况下,绑定到1个cpu比多个cpu执行更快(上下文切换,resume、yield)
so,萌生了一个想法,Java中通过JNI指定线程在第几个cpu上执行。
这篇文章,首先要做的是通过JNI调用线程执行。
JNI调用可以参考这篇文章 Linux下测试Java的JNI(Java Native Interface)
我的系统和作者是一样的Ubuntu 12.04,但是采用文中提到的gcc编译动态链接库的方式,生成.so后,通过Java调用一直会报错“symbol lookup error: libcpu.so: undefined symbol: _Znwj”
咨询好友林克后,他给出了编译方式。
g++ -std=c++0x -I/home/jjf/hadoop/jdk1.6.0_45/include/linux/ -I/home/jjf/hadoop/jdk1.6.0_45/include/ -O0 -g3 -Wall -c -fmessage-length=0 -fPIC -MMD -MP -MF"SetCpu.d" -MT"SetCpu.d" -o "SetCpu.o" "SetCpu.cpp" g++ -shared -o "libcpu.so" ./SetCpu.o
其中/home/jjf/hadoop/jdk1.6.0_45是JDK安装目录
然后将生成的libcpu.so移到$java.library.path目录下
至于如何调用线程执行呢,参考了interface java with C timer library using JNI
感谢强大的stackoverflow!!!!! 不解释
SetCpu.java
public class SetCpu { static { System.loadLibrary("cpu"); } public static native int getCpu(Runnable r); }
CpuMain.java
public class CpuMain { public static void main(String[] args) { System.out.println(SetCpu.getCpu(new Runnable() { @Override public void run() { System.out.println("cpu"); } })); } }
SetCpu.h 是通过命令
javah -jni SetCpu生成的
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class SetCpu */ #ifndef _Included_SetCpu #define _Included_SetCpu #ifdef __cplusplus extern "C" { #endif /* * Class: SetCpu * Method: getCpu * Signature: (Ljava/lang/Runnable;)I */ JNIEXPORT jint JNICALL Java_SetCpu_getCpu (JNIEnv *, jclass, jobject); #ifdef __cplusplus } #endif #endif
SetCpu.cpp
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include "SetCpu.h" /* Header for class SetCpu */ #ifdef __cplusplus extern "C" { #endif struct ThreadParams { JavaVM *jvm; jobject callback; }; void *myfun(void *ptr) { ThreadParams* p = reinterpret_cast(ptr); JavaVM *jvm = p->jvm; jobject callback = p->callback; free(p); JNIEnv *env = NULL; jint res; res = jvm->AttachCurrentThread((void **)&env, NULL); if(res < 0) { fprintf(stderr, "Attach VM Thread failed\n"); return NULL; } jclass RunnableInterface = env->GetObjectClass(callback); jmethodID Run = env->GetMethodID(RunnableInterface, "run","()V"); env->CallVoidMethod(callback, Run); jvm->DetachCurrentThread(); pthread_exit(NULL); } /* * Class: SetCpu * Method: getCpu * Signature: (Ljava/lang/Runnable;)I */ JNIEXPORT jint JNICALL Java_SetCpu_getCpu(JNIEnv *env, jclass obj, jobject r) { pthread_t tid; ThreadParams* ptr = new ThreadParams(); JavaVM *jvm = NULL; env->GetJavaVM(&jvm); ptr->callback = env->NewGlobalRef(r); ptr->jvm = jvm; jint errInt = -1; jint sucInt = 1; if (pthread_create(&tid, NULL, myfun, reinterpret_cast (ptr)) != 0) { fprintf(stderr, "thread create failed\n"); return errInt; } pthread_join(tid, NULL); return sucInt; } #ifdef __cplusplus } #endif
执行结果当然是 cpu 1