【Android】线程/进程绑定指定CPU核
参考文档:
https://blog.csdn.net/lanyzh0909/article/details/50404664 //线程绑定CPU核-sched_setaffinity
https://blog.csdn.net/lyx2007825/article/details/53885205 //android将线程绑定在指定CPU
https://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 /* Header for class com_example_myapplication_Affinity */#ifndef _Included_com_example_myapplication_Affinity#define _Included_com_example_myapplication_Affinity#ifdef __cplusplusextern "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 #include #include #include #include #include #include #include #include#include#include#include#include#define __USE_GNU#include#include#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)#endifstatic 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"?> ......
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
- 如果编译正常会出现下图。
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
查询出来的结果(取与本应用相关的信息)如下:
在我的代码中,在应用启动的进程下开了两个子线程,在新开的myservice进程中,开了四个子线程。最后一列的NAME默认情况下,是包名。
PID 9105是应用程序所在进程,PID 9132是应用程序下的主线程,也就是绘制UI的线程,PID 9134和9135是应用程序下的两个子线程。
PID 9136是myservice所在进程,下面的Thread-62到65是myservice下的子线程。
从上面的图片可以看到,如果在进程中绑定了cpu核,子线程也会绑定到那个核上;如果在子线程中绑定了与主线程不同的核,也是可以的。
6. 遇到的问题
1. dlopen failed: “/data/app-lib/com.example.myapplication-2/libAffinity.so” has unexpected e_machine: 40
我是在模拟器上运行的,这个问题的解决办法是在Application.mk中加生成的文件:
APP_PLATFORM := android-16APP_ABI := armeabi-v7a,x86
build.gradle中同步添加:
android { defaultConfig { ... ndk { moduleName "libAffinity" ldLibs "log" abiFilters "armeabi-v7a","x86" } } ...}
源码地址:https://download.csdn.net/download/a569503963/10917571
更多相关文章
- Android 文件操作大全
- android中加载assets中的资源文件
- Android JNI 开启子线程后调用 Activity 方法更新UI
- Android开发 - 丰富常用的颜色文件colors.xml
- 学习Android之setDataAndType(利用第三方应用程序打开各种文件)
- Android多线程