code小生,一个专注 Android 领域的技术平台
公众号回复 Android 加入我的安卓技术群
作者:尛尛球 链接:https://blog.csdn.net/a569503963/article/details/86149495 声明:本文来自尛尛球
投稿,转发等请联系原作者授权
参考文档: https://blog.csdn.net/lanyzh0909/article/details/50404664 //线程绑定CPU核-sched_setaffinityhttps://blog.csdn.net/lyx2007825/article/details/53885205 //android将线程绑定在指定CPUhttps://www.jianshu.com/p/568cbc3ef786 //将C文件通过NDK编译生成SO库https://my.oschina.net/zhiweiofli/blog/138454 //Android的ps命令介绍和技巧
功能:获取CPU当前核数,将线程/进程绑定到指定CPU核上
原理:利用jni将线程绑定到指定的CPU核上
要说的话:
此文使用的方式是先编译完so文件,然后将so文件放入项目中使用的 。不是直接在项目中放入c代码运行。将c代码直接放入项目时我的项目会在c代码的位置报错,所以采用了先编译成so文件的方式,如果你的项目不报错,可以参考上面第三个文档,将代码直接放入项目中。
h文件、c文件和两个mk文件要在同一文件夹下,ndk编译命令需要在AndroidStudio的Terminal中执行,在外部命令行运行需要指定mk文件地址,可以自行查找命令。
1. c代码: 1.1 com_example_myapplication_Affinity.h文件 /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_myapplication_Affinity */ #ifndef _Included_com_example_myapplication_Affinity #define _Included_com_example_myapplication_Affinity #ifdef __cplusplus extern "C" {#endif /* * Class: com_example_myapplication_Affinity * Method: bindToCpu * Signature: (I)V */ JNIEXPORT void JNICALL Java_com_example_myapplication_Affinity_bindToCpu (JNIEnv *, jclass, jint) ;/* * Class: com_example_myapplication_Affinity * Method: getCores * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_example_myapplication_Affinity_getCores (JNIEnv *, jclass) ;#ifdef __cplusplus }#endif #endif
1.2 Affinity.c文件 #include <jni.h> #include <android/log.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <pthread.h> #include <sys/syscall.h> #include <com_example_myapplication_Affinity.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/sysinfo.h> #include <unistd.h> #define __USE_GNU #include <sched.h> #include <ctype.h> #define THREAD_MAX_NUM 100 //1个CPU内的最多进程数 int num=0 ; //cpu中核数 #define TAG "Affinity" #define DEBUG 1 #ifndef CPU_ZERO #define CPU_SETSIZE 1024 #define __NCPUBITS (8 * sizeof (unsigned long)) typedef struct { unsigned long __bits[CPU_SETSIZE / __NCPUBITS]; } cpu_set_t ;#define CPU_SET(cpu, cpusetp) \ ((cpusetp)->__bits[(cpu)/__NCPUBITS] |= (1UL << ((cpu) % __NCPUBITS))) #define CPU_ZERO(cpusetp) \ memset((cpusetp), 0, sizeof(cpu_set_t)) #else #define CPU_SET(cpu,cpustep) ((void)0) #define CPU_ZERO(cpu,cpustep) ((void)0) #endif #ifdef DEBUG #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__) #else #define LOGD(...) ((void)0) #define LOGE(...) ((void)0) #endif static int getCores () { return sysconf(_SC_NPROCESSORS_CONF); }JNIEXPORT int JNICALL Java_com_example_myapplication_Affinity_getCores (JNIEnv *env, jclass type) { return getCores(); }JNIEXPORT void JNICALL Java_com_example_myapplication_Affinity_bindToCpu (JNIEnv *env, jclass type, jint cpu) { int cores = getCores(); LOGD("get cpu number = %d\n" ,cores); if (cpu >= cores) { LOGE("your set cpu is beyond the cores,exit..." ); return ; } cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(cpu,&mask); if (sched_setaffinity(0 , sizeof (mask), &mask) == -1 )//设置线程CPU亲和力 { LOGD("warning: could not set CPU affinity, continuing...\n" ); }else { LOGD("set affinity to %d success" ,cpu); } }
1.3 要点: c文件的方法与h文件的方法一致,包括方法名、传入参数、返回参数,全都一致。
h文件可以先写java的native方法,调用命令创建。
1.4 备注 1.4.1 调用命令创建.h文件:
写java文件,并写上native方法
package com.example.myapplication;public class Affinity { static { System.loadLibrary("Affinity" ); } public static native void bindToCpu (int cpu) ; public static native int getCores () ; }
在Terminal使用命令
先进入工程main目录下 输入自己的Native.class文件的绝对路径 javah -d jni -classpath class路径 包名+类名
例: javah -d jni -classpath D:\Demo\JNITest\app\build\intermediates\classes\debug com.example.myapplication.Affinity
注意:debug后面要留空格
2. mk文件 2.1 Application.mk文件 APP_PLATFORM := android-16 //编译环境 APP_ABI := armeabi-v7a //编译后生成so的文件夹
2.2 Android.mk文件 LOCAL_PATH := $(call my-dir ) include $(CLEAR_VARS) LOCAL_MODULE := libAffinity //生成后的so文件名 LOCAL_SRC_FILES := Affinity.c //要生成的c文件 LOCAL_LDLIBS := -llog -lzinclude $(BUILD_SHARED_LIBRARY)
2.3 AndroidManifest.xml文件 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android ="http://schemas./apk/res/android" package ="com.example.myapplication" > <uses-sdk android:minSdkVersion ="16" android:targetSdkVersion ="25" > </uses-sdk > <application ... > ...... </application > </manifest >
2.4 要点 APP_PLATFORM的值必须和AndroidManifest.xml中android:minSdkVersion的值相同
c文件、h文件、两个mk文件,都放在同一目录下
3. 编译成so文件 在AndroidStudio中打开Terminal。
进入到c文件所在文件夹。
使用ndk-build命令。如果你的ndk目录没有配置到环境变量中,使用路径的方式也可以,如:C:\User\admin\Android\sdk\ndk_bundle\ndk-build.cmd
如果编译正常会出现下图。
ndk编译成功 4. 将so文件放入项目中 复制so文件到app\libs中
在项目的build.gradle中,设置jni目录
android{ ... sourceSets { main { jniLibs.srcDirs = ['libs' ] } } }
5. 查询是否绑定CPU成功 代码运行成功会出现log信息“set affinity to 0 success”,这里0代表cpu编号
使用linux命令查询
adb shell ps -t -p -c
查询出来的结果(取与本应用相关的信息)如下:
查询线程所在cpu 在我的代码中,在应用启动的进程下开了两个子线程,在新开的 myservice 进程中,开了四个子线程。最后一列的 NAME 默认情况下,是包名。 PID 9105 是应用程序所在进程,PID 9132 是应用程序下的主线程,也就是绘制UI的线程,PID 9134 和 9135 是应用程序下的两个子线程。 PID 9136 是 myservice 所在进程,下面的 Thread-62 到 65 是myservice 下的子线程。
从上面的图片可以看到,如果在进程中绑定了cpu核,子线程也会绑定到那个核上;如果在子线程中绑定了与主线程不同的核,也是可以的。
分享技术我是认真的