参考文档:
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核上

要说的话:

  1. 此文使用的方式是先编译完so文件,然后将so文件放入项目中使用的。不是直接在项目中放入c代码运行。将c代码直接放入项目时我的项目会在c代码的位置报错,所以采用了先编译成so文件的方式,如果你的项目不报错,可以参考上面第三个文档,将代码直接放入项目中。
  2. 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 要点:

  1. c文件的方法与h文件的方法一致,包括方法名、传入参数、返回参数,全都一致。
  2. h文件可以先写java的native方法,调用命令创建。

1.4 备注

1.4.1 调用命令创建.h文件:

  1. 写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();}
  1. 在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 要点

  1. APP_PLATFORM的值必须和AndroidManifest.xml中android:minSdkVersion的值相同
  2. c文件、h文件、两个mk文件,都放在同一目录下

3. 编译成so文件

  1. 在AndroidStudio中打开Terminal。
  2. 进入到c文件所在文件夹。
  3. 使用ndk-build命令。如果你的ndk目录没有配置到环境变量中,使用路径的方式也可以,如:C:\User\admin\Android\sdk\ndk_bundle\ndk-build.cmd
  4. 如果编译正常会出现下图。
    【Android】线程/进程绑定指定CPU核_第1张图片

4. 将so文件放入项目中

  1. 复制so文件到app\libs中
  2. 在项目的build.gradle中,设置jni目录
android{...sourceSets {        main {            jniLibs.srcDirs = ['libs']        }    }}

5. 查询是否绑定CPU成功

  1. 代码运行成功会出现log信息“set affinity to 0 success”,这里0代表cpu编号
  2. 使用linux命令查询
adb shell ps -t -p -c

查询出来的结果(取与本应用相关的信息)如下:
【Android】线程/进程绑定指定CPU核_第2张图片

在我的代码中,在应用启动的进程下开了两个子线程,在新开的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

更多相关文章

  1. Android 文件操作大全
  2. android中加载assets中的资源文件
  3. Android JNI 开启子线程后调用 Activity 方法更新UI
  4. Android开发 - 丰富常用的颜色文件colors.xml
  5. 学习Android之setDataAndType(利用第三方应用程序打开各种文件)
  6. Android多线程

随机推荐

  1. Android(安卓)M 新的运行时权限开发者需
  2. 2021还能学Android吗?我的“零”基础——
  3. Android(安卓)插件化 动态升级
  4. Android中WebView加载本地Html,与JavaScri
  5. 作为一个刚刚入职Android开发的应届生,该
  6. 深入Android(安卓)【一】 —— 序及开篇
  7. NDK版本与Android固件要求对应表
  8. Android系统发展历程:1.0到4.0及代表机型
  9. 新书内容连载(3):Android(安卓)SDK中常用命
  10. 深入探讨 Android(安卓)传感器