code小生,一个专注 Android 领域的技术平台
公众号回复 Android 加入我的安卓技术群
作者:尛尛球
链接:https://blog.csdn.net/a569503963/article/details/86149495
声明:本文来自尛尛球
投稿,转发等请联系原作者授权
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文件地址,可以自行查找命令。
/* 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 __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
#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)
#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);
}
}
c文件的方法与h文件的方法一致,包括方法名、传入参数、返回参数,全都一致。
h文件可以先写java的native方法,调用命令创建。
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后面要留空格
APP_PLATFORM := android-16 //编译环境
APP_ABI := armeabi-v7a //编译后生成so的文件夹
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libAffinity //生成后的so文件名
LOCAL_SRC_FILES := Affinity.c //要生成的c文件
LOCAL_LDLIBS := -llog -lz
include $(BUILD_SHARED_LIBRARY)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25">uses-sdk>
<application
...>
......
application>
manifest>
APP_PLATFORM的值必须和AndroidManifest.xml中android:minSdkVersion的值相同
c文件、h文件、两个mk文件,都放在同一目录下
在AndroidStudio中打开Terminal。
进入到c文件所在文件夹。
使用ndk-build命令。如果你的ndk目录没有配置到环境变量中,使用路径的方式也可以,如:C:\User\admin\Android\sdk\ndk_bundle\ndk-build.cmd
如果编译正常会出现下图。
复制so文件到app\libs中
在项目的build.gradle中,设置jni目录
android{
...
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
代码运行成功会出现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核,子线程也会绑定到那个核上;如果在子线程中绑定了与主线程不同的核,也是可以的。
分享技术我是认真的