Android nice在进程与线程调度中的作用

本文介绍了Android中进程和线程的概念,并详细探讨了nice值在进程优先级调整中的应用,包括如何使用nice和renice命令,以及Android与JAVA线程优先级的区别。

基本概念:

进程:计算机进行资源分配和高度的基本单位,是程序运行的实体,也是线程的容器。

线程:是进程中实际执行的单元,是程序执行的最小单元,属于一个进程。

一个进程可以拥有多个线程。

 

nice在进程调试中作用

在Android中,可以使用nice值来设定一个进程的优先级,系统的调度器可以根据nice值来合理的调度进程,主要特点如下:

  • 在Android中,nice的取值范围为-20~19
  • 在Android中,nice值的默认大小为0
  • 在Android中,nice值越大,进程的优先级越低,获得的CPU调用机会就越少;nice值越高,进程的优先级越高,获得的CPU调用机会越多
  • 在Android中,父进程fork出来的子进程nice值与父进程相同,你进程renice后,子进程的nice值不会改变

 

如何更改进程的nice值

Android中可用如下命令更改进程的nice值,

  • usage: nice [-n PRIORITY] command [args...]

    Run a command line at an increased or decreased scheduling priority.

    Higher numbers make a program yield more CPU time, from -20 (highest
    priority) to 19 (lowest).  By default processes inherit their parent's
    niceness (usually 0).  By default this command adds 10 to the parent's
    priority.  Only root can set a negative niceness level.

 

  • USAGE: renice [[-r] [-t TYPE] priority pids ...] [-g pid]

其中nice命令用于设置一个新创建的进程的优先级,而renice命令用于更改已经创建的进程的优先级,且这两个命令都需要在root权限下运行。

 

线程调度

在Android开发中,我们用的最多的是对于线程优先级的控制,但在Android中,出现了两种版本的线程优先级控制:JAVA版本和Android版本,两种版本的优先级的主要差别如下:

  • JAVA版本中的优先级使用java.lang.Thread中的setPriority(int priority)和getPriority()设置和获得线程的优先级,其只包括三种类型的线程优先级,属于粗粒度控制,如下:

 

       public static final intMAX_PRIORITY = 10

       public static final intMIN_PRIORITY = 5

       public static final intMIN_PRIORITY = 1

 

  而Android版本中的线程优先级使用android.os.Process类中的setThreadPriority(int priority)和getPriority()设置和  获得线程的优先级,其包括10中线程优先级,相对于JAVA的属于细粒度控制策略,如下:

   

  因此,在设置和获取线程优先级时,建议使用Android版本的API。

  • Android API的线程优先级和JAVA原生API的优先级是相对独立的,比如使用 android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND) 后,使用Java原生API,Thread.getPriority()得到的值不会改变。

由于上术第二点的差别,导致在分析ANR log时需要格外注意,在下面的ANR日志信息中,prio=5中proi的值对应的JAVA原生API的线程优先级。而nice=-6中的nice表示的Android API版本的线程优先级。

"main" prio=5 tid=1 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x41690f18 self=0x4167e650
  | sysTid=1765 nice=-6 sched=0/0 cgrp=apps handle=1074196888
  | state=S schedstat=( 0 0 0 ) utm=5764 stm=3654 core=2
  #00  pc 00022624  /system/lib/libc.so (__futex_syscall3+8)
  #01  pc 0000f054  /system/lib/libc.so (__pthread_cond_timedwait_relative+48)
  #02  pc 0000f0b4  /system/lib/libc.so (__pthread_cond_timedwait+64)

<think>我们正在讨论的是在Android HAL层设置进程线程优先级的方法。根据之前的引用,我们知道在应用层可以使用`Process.setThreadPriority()`和`Thread.setPriority()`,但在HAL层(属于Native层,通常用C/C++编写)则需要使用系统提供的原生API。 在Android HAL层,我们通常使用Linux系统调用来设置线程优先级。具体来说,可以使用`setpriority`系统调用来设置进程(或线程)的优先级,或者使用`sched_setscheduler`来设置调度策略和优先级。对于线程,我们也可以使用`pthread_setschedparam`函数。 ### 设置线程优先级 在Linux中,线程是轻量级进程(LWP),因此我们可以使用设置进程优先级的函数来设置线程优先级。但是,更推荐使用POSIX线程调度函数。 1. **使用`setpriority`**: 这个函数可以设置进程进程组或用户的优先级。其函数原型为: ```c #include <sys/resource.h> int setpriority(int which, id_t who, int prio); ``` 其中,`which`可以是`PRIO_PROCESS`(针对进程)、`PRIO_PGRP`(针对进程组)或`PRIO_USER`(针对用户)。`who`是对应的ID(进程ID、进程组ID或用户ID),0表示当前调用者。`prio`是优先级值,范围从-20(最高优先级)到19(最低优先级)。 注意:这个函数设置的是整个进程的优先级(即主线程的优先级),如果要对特定线程设置,需要使用其他方法。 2. **使用`pthread_setschedparam`**: 这是专门为线程设置的函数。需要包含头文件`<pthread.h>`和`<sched.h>`。 ```c #include <pthread.h> #include <sched.h> int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); ``` 其中,`thread`是线程ID(可以通过`pthread_self()`获取当前线程ID),`policy`是调度策略(如`SCHED_FIFO`, `SCHED_RR`, `SCHED_OTHER`),`param`是一个结构体,其中包含`sched_priority`字段,表示优先级。 注意:使用`SCHED_FIFO`或`SCHED_RR`需要root权限或者相应的capability(在Android系统中,通常只有系统进程才能使用)。 ### 设置进程优先级 在HAL层,设置进程优先级同样可以使用`setpriority`函数。另外,也可以使用`nice`函数(但`nice`函数只能降低优先级,除非有权限才能提高)。 ### 在Android HAL中的注意事项 - 在Android HAL中,由于权限限制,通常不能随意提高优先级。特别是实时调度策略(如`SCHED_FIFO`)需要特权,一般只有系统核心进程才能使用。 - 在HAL层中,如果是在一个由Android系统启动的守护进程中,可以在进程启动时设置其优先级。如果是被binder调用的线程,则可以在该线程中设置优先级。 ### 示例代码 以下是一个在HAL层设置当前线程优先级的示例(使用`pthread_setschedparam`): ```c #include <pthread.h> #include <sched.h> void set_current_thread_priority(int priority) { pthread_t this_thread = pthread_self(); struct sched_param params; params.sched_priority = priority; int policy = SCHED_FIFO; // 或者SCHED_RR,但需要权限 // 如果不需要实时调度,可以使用SCHED_OTHER,然后通过nice值调整 // 注意:SCHED_OTHER策略下,优先级必须为0 if (pthread_setschedparam(this_thread, policy, &params) != 0) { // 处理错误 } } ``` 但是,由于Android设备通常不允许普通进程使用`SCHED_FIFO`或`SCHED_RR`,因此更常见的做法是使用`setpriority`来设置nice值: ```c #include <sys/resource.h> void set_current_thread_nice(int nice_value) { // 注意:setpriority设置的是进程的优先级,但在多线程中,设置当前线程的优先级需要指定线程ID(TID) // 但是setpriority的PRIO_PROCESS是针对进程(即主线程)的,所以不能直接设置其他线程。 // 对于非主线程,我们可以使用如下方式: pid_t tid = gettid(); // 获取当前线程的TID setpriority(PRIO_PROCESS, tid, nice_value); } ``` 注意:`gettid()`函数在Android中可用,但需要包含头文件`<unistd.h>`。 然而,在多线程环境中,每个线程都有自己的优先级(nice值)。在Linux中,线程nice值是进程内共享的(在较新的内核中,线程可以有自己的nice值,但setpriority的PRIO_PROCESS作用于整个进程)。所以,更推荐使用`sched_setscheduler`或`pthread_setschedparam`来设置线程优先级。 ### 总结 在Android HAL层设置线程优先级: 1. 如果只需要调整nice值(相对优先级),可以使用`setpriority`(注意:在较新的内核中,线程可以有自己的nice值,但Android可能有限制)。 2. 如果需要设置实时优先级,使用`pthread_setschedparam`,但需要确保有权限。 在实际开发中,建议先尝试使用`setpriority`设置nice值,因为实时调度策略通常受限。 ### 相关问题 1. 在Android HAL层中,如何获取当前线程的TID? 2. 设置实时调度策略(如`SCHED_FIFO`)需要什么权限?在Android中如何配置? 3. 在Android HAL中,如何设置进程的优先级?</think>在 Android HAL(Hardware Abstraction Layer)层设置进程线程优先级,需要使用 Linux 系统级的 API 而非 Java 层的 API。以下是具体实现方法: ### 一、设置线程优先级 在 HAL 层(C/C++ 代码)中推荐使用 POSIX 线程优先级 API: ```c #include <pthread.h> #include <sched.h> void set_native_thread_priority(int priority) { pthread_t this_thread = pthread_self(); struct sched_param params; params.sched_priority = priority; // 范围:1(low)-99(high) // 设置实时调度策略(需要 root 权限) int ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params); if (ret != 0) { // 备选方案:设置普通优先级 setpriority(PRIO_PROCESS, 0, priority); } } ``` ### 二、设置进程优先级 使用 `setpriority()` 系统调用: ```c #include <sys/resource.h> void set_native_process_priority(int nice_value) { // nice值范围:-20(最高) 到 19(最低) setpriority(PRIO_PROCESS, 0, nice_value); } ``` ### 三、Android 系统权限要求 1. **关键配置**: - 在 `Android.bp` 或 `Android.mk` 中添加: ```makefile shared_libs: ["libcutils"] ``` - 在 `sepolicy` 中声明: ```te setpriority:process { setpriority } sched_setscheduler:process { setsched } ``` 2. **实时调度策略限制**: - `SCHED_FIFO/SCHED_RR` 需要 **root 权限** 或 `CAP_SYS_NICE` 能力 - 普通进程只能使用 `SCHED_OTHER` 策略 ### 四、最佳实践建议 1. **HAL 线程优先级**: ```c // 设置高优先级(但避免过高影响系统) set_native_thread_priority(50); ``` 2. **进程优先级**: ```c // 设置略高于默认的优先级 set_native_process_priority(-5); ``` > **重要提示**:过度提高优先级可能导致系统稳定性问题,建议通过 `systrace` 验证实际调度效果[^2]。在 Android 10 及以上版本,需注意 cgroups 对进程优先级的限制[^1]。 ### 五、备选方案 若无 root 权限,可通过 Binder 调用到系统服务设置: ```java // 在 JNI 层调用 Android API AndroidRuntime::callStaticMethod("android/os/Process", "setThreadPriority", "(I)V", priority); ``` --- ### 相关问题 1. 如何在 Android HAL 层中测量线程的实际调度延迟? 2. 设置 `SCHED_FIFO` 策略时遇到权限拒绝如何解决? 3. Android 的 cgroups 如何影响进程优先级设置? 4. 在非 root 设备上提升 HAL 线程优先级的替代方案有哪些? 5. 如何通过 systrace 验证线程优先级设置的实际效果? [^1]: Android 线程优先级设置存在 cgroups 限制,过度提高可能导致反效果 [^2]: 推荐使用 systrace 工具验证实际调度行为 [^3]: HAL 层开发需深入理解 Linux 调度机制
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值