Java线程绑定到具体的cpu上执行


上文通过JNI调用线程执行已经实现了通过JNI调用Java线程执行。

本文就是说明如何设置线程执行的cpu?

参考Linux中线程与CPU核的绑定就可以设置

本文的代码已经开源在我的GitHub上threadBandCpu

如何将线程绑定到cpu的呢?这里有几个函数(来自参考文章)

int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,
const cpu_set_t *cpuset);

int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, 
cpu_set_t *cpuset);

//初始化,设为空
void CPU_ZERO (cpu_set_t *set); 
//将某个cpu加入cpu集中 
void CPU_SET (int cpu, cpu_set_t *set); 
//将某个cpu从cpu集中移出 
void CPU_CLR (int cpu, cpu_set_t *set); 
//判断某个cpu是否已在cpu集中设置了 
int CPU_ISSET (int cpu, const cpu_set_t *set); 

这里贴一下几条重要的命令,可能与上文有所重复

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"ThreadBandCpu.d" -MT"ThreadBandCpu.d" -o "ThreadBandCpu.o" "ThreadBandCpu.cpp"

g++ -shared -o "libbandCpu.so" ./ThreadBandCpu.o

其中/home/jjf/hadoop/jdk1.6.0_45是JDK安装目录

ThreadBandCpu.java

public class ThreadBandCpu {
    static {
        System.loadLibrary("bandCpu");
    }
    public static native void bandCpu(Runnable r, int cpu);
}

BandCpuTest.java

public class BandCpuTest {
    public static void main(String[] args) {
        ThreadBandCpu.bandCpu(new Runnable() {
            
            @Override
            public void run() {
                for(;;){}
            }
        }, 2);
    }
}

ThreadBandCpu.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ThreadBandCpu */

#ifndef _Included_ThreadBandCpu
#define _Included_ThreadBandCpu
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     ThreadBandCpu
 * Method:    bandCpu
 * Signature: (Ljava/lang/Runnable;I)V
 */
JNIEXPORT void JNICALL Java_ThreadBandCpu_bandCpu
  (JNIEnv *, jclass, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

ThreadBandCpu.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 <sched.h>
#include "ThreadBandCpu.h"
/* Header for class ThreadBandCpu */
#ifdef __cplusplus
extern "C" {
#endif

struct ThreadParams
{
    JavaVM *jvm;
    jobject callback;
    int cpu;
};

void *myfun(void *ptr)
{
    ThreadParams* p = reinterpret_cast(ptr);
    JavaVM *jvm = p->jvm;
    jobject callback = p->callback;
    int num = p->cpu % sysconf(_SC_NPROCESSORS_CONF);
    free(p);

    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(num, &mask);
    if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0) {
        fprintf(stderr, "set thread affinity failed\n");
    }

    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:     ThreadBandCpu
 * Method:    bandCpu
 * Signature: (Ljava/lang/Runnable;I)V
 */
JNIEXPORT void JNICALL Java_ThreadBandCpu_bandCpu(JNIEnv *env, jclass cls, jobject obj, jint cpu) {
    pthread_t tid;
    ThreadParams* ptr = new ThreadParams();
    JavaVM *jvm = NULL;

    env->GetJavaVM(&jvm);
    ptr->callback = env->NewGlobalRef(obj);
    ptr->jvm = jvm;
    ptr->cpu = (int)cpu;

    if (pthread_create(&tid, NULL, myfun, reinterpret_cast(ptr)) != 0) {
        fprintf(stderr, "thread create failed\n");
        return ;
    }
    pthread_join(tid, NULL);
}

#ifdef __cplusplus
}
#endif

上篇: 通过JNI调用线程执行 下篇: 深入JVM内部了解Java线程的创建与执行