剖析Android中进程与线程调度之nice

关注微信号:javalearns   随时随地学Java

或扫一扫

随时随地学Java

在计算机操作系统中,进程是进行资源分配和调度的基本单位,同时每个进程之内也可以存在多个线程。那么在Android系统(Linux Kernel)中,进程是如何去抢占资源,线程又是如何根据优先级切换呢,本文将尝试剖析这个问题,研究nice在Linux以及Android系统中的应用。

一些概念

  • 进程 是计算机系统中,程序运行的实体,也是线程的容器。
  • 线程 是进程中实际执行单位,一个线程是程序执行流的最小单元。在一个进程中可以有多个线程存在。

nice与进程调度

Linux中,使用nice value(以下成为nice值)来设定一个进程的优先级,系统任务调度器根据nice值合理安排调度。

  • nice的取值范围为-20到19。
  • 通常情况下,nice的默认值为0。视具体操作系统而定。
  • nice的值越大,进程的优先级就越低,获得CPU调用的机会越少,nice值越小,进程的优先级则越高,获得CPU调用的机会越多。
  • 一个nice值为-20的进程优先级最高,nice值为19的进程优先级最低。
  • 父进程fork出来的子进程nice值与父进程相同。父进程renice,子进程nice值不会随之改变。

词源考究

nice这个命令的来源几乎没有资料提到,于是便尝试自己来推断一下。在诸如词霸,沪江等词典给出的意思均为好的;美好的;可爱的;好心的,友好的。而有道词典则稍微给出了一个其他词典没有的和蔼的。个人认为有道给出的这个比较合理。要想做到和蔼,就需要做到谦让,因此或多或少牺牲自己一点,成全他人。所以nice值越高,越和蔼,但是自己的优先级也会越低。

renice

对于一个新的进程我们可以按照下面的代码为一个进程设定nice值。

nice -n 10 adb logcat 

对于已经创建的进程,我们可以使用renice来修改nice值

sudo renice -n 0 -p 24161 

该命令需要使用root权限,-p对应的值为进程id。

注意renice命令在Linux发行版中-n 的值应该为进程的目标优先级。而Mac下-n,则是代表对当前权限的增加值。 比如在Mac下,讲一个进程的nice值由19改成10,可以这样操作sudo renice -n -9 -p 24161,这一点需要注意,避免掉进坑里。

Android中的nice

由于Android基于Linux Kernel,在Android中也存在nice值。但是一般情况下我们无法控制,原因如下:

  • Android系统并不像其他Linux发行版那样便捷地使用nice命令操作。
  • renice需要root权限,一般应用无法实现。

线程调度

虽然对于进程的优先级,我们无法控制,但是我们可以控制进程中的线程的优先级。在Android中有两种线程的优先级,一种为Android API版本,另一种是 Java 原生版本。

Android API

Android中的线程优先级别目前规定了如下,了解了进程优先级与nice值的关系,那么线程优先级与值之间的关系也就更加容易理解。

  • THREAD_PRIORITY_DEFAULT,默认的线程优先级,值为0。
  • THREAD_PRIORITY_LOWEST,最低的线程级别,值为19。
  • THREAD_PRIORITY_BACKGROUND 后台线程建议设置这个优先级,值为10。
  • THREAD_PRIORITY_FOREGROUND 用户正在交互的UI线程,代码中无法设置该优先级,系统会按照情况调整到该优先级,值为-2。
  • THREAD_PRIORITY_DISPLAY 也是与UI交互相关的优先级界别,但是要比THREAD_PRIORITY_FOREGROUND优先,代码中无法设置,由系统按照情况调整,值为-4。
  • THREAD_PRIORITY_URGENT_DISPLAY 显示线程的最高级别,用来处理绘制画面和检索输入事件,代码中无法设置成该优先级。值为-8。
  • THREAD_PRIORITY_AUDIO 声音线程的标准级别,代码中无法设置为该优先级,值为 -16。
  • THREAD_PRIORITY_URGENT_AUDIO 声音线程的最高级别,优先程度较THREAD_PRIORITY_AUDIO要高。代码中无法设置为该优先级。值为-19。
  • THREAD_PRIORITY_MORE_FAVORABLE 相对THREAD_PRIORITY_DEFAULT稍微优先,值为-1。
  • THREAD_PRIORITY_LESS_FAVORABLE 相对THREAD_PRIORITY_DEFAULT稍微落后一些,值为1。

使用Android API为线程设置优先级也很简单,只需要在线程执行时调用android.os.Process.setThreadPriority方法即可。这种在线程运行时进行修改优先级,效果类似renice。

new Thread () {
    @Override
    public void run() {
      super.run();
        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    }
}.start();

Java原生API

Java为Thread提供了三个级别的设置,

  • MAX_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY,值为10。
  • MIN_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_LOWEST,值为0。
  • NORM_PRIORITY,相当于android.os.Process.THREAD_PRIORITY_DEFAULT,值为5。

使用setPriority我们可以为某个线程设置优先级,使用getPriority可以获得某个线程的优先级。

在Android系统中,不建议使用Java原生的API,因为Android提供的API划分的级别更多,更适合在Android系统中进行设定细致的优先级。

注意

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

new Thread() {
    @Override
    public void run() {
        super.run();
        Log.i(LOGTAG, "Java Thread Priority Before=" + Thread.currentThread().getPriority());
        Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
        Log.i(LOGTAG, "Java Thread Priority=" + Thread.currentThread().getPriority());
    }
}.start();

上述代码的运行日志为

I/MainActivity( 3679): Java Thread Priority Before=5  I/MainActivity( 3679): Java Thread Priority=5 

由于上面的这一点缺陷,导致我们在分析ANR trace时需要注意,在下面的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)

避免ANR

我在之前的文章说说Android中的ANR中提到使用WorkerThread处理耗时IO操作,同时将WorkerThread的优先级降低,对于耗时IO操作,比如读取数据库,文件等,我们可以设置该workerThread优先级为THREAD_PRIORITY_BACKGROUND,以此降低与主线程竞争的能力。


.................... 【.........阅读全文】

Java免费学习   Java自学网 http://www.javalearns.com

关注微信号:javalearns   随时随地学Java

或扫一扫

随时随地学Java


<think>嗯,用户想了解Android中音频进程调度等级以及如何设置或调整。首先,我需要回忆一下Android系统中进程调度的相关知识。记得Android是基于Linux内核的,所以进程调度策略应该和Linux的类似,比如有SCHED_FIFO、SCHED_RR和SCHED_OTHER这些策略。实时进程通常会使用SCHED_FIFO或SCHED_RR,而普通进程用SCHED_OTHER。 然后,用户提到的音频进程可能属于实时进程,因为音频处理对延迟要求很高。比如AAudioService中的client线程设置为实时策略,这个在引用[1]里有提到,应该是一个关键点。需要解释为什么音频进程需要更高的优先级,可能涉及到防止卡顿和确保低延迟。 接下来,用户想知道具体的设置方法。在Android中,设置进程调度等级通常涉及到调用Linux的系统API,比如sched_setscheduler,或者使用Android提供的封装方法。比如在Native层可以使用pthread_setschedparam,而在Java层可能需要通过某些系统服务或者调用Native方法来实现。不过,普通应用可能没有权限修改调度策略,需要系统级权限或者签名权限。 另外,引用[2]提到在Android 15中,进程优先级方案可能有所调整,特别是当进程拿不到CPU和IO资源时如何提高优先级。这可能涉及到设置调度策略和优先级,以及调整IO优先级,比如使用ioprio_set系统调用。不过这部分可能需要更深入的分析,比如具体在代码中如何实现。 还需要考虑实际应用中的例子,比如在AAudioService中如何设置client线程的优先级。根据引用[1],是通过requestPriority()方法设置的。这可能涉及到Android框架中的内部API,比如在C++层调用setpriority或sched_setscheduler函数。 不过,用户可能需要具体的代码示例,比如在Native层如何设置线程调度策略和优先级。例如,使用pthread库创建线程后,设置其策略为SCHED_FIFO,并指定优先级。但需要注意权限问题,普通应用可能无法成功设置,需要系统权限或者应用位于特定的组(如audio组)才有权限。 此外,还要提到Android进程优先级管理,比如使用android.os.Process.setThreadPriority方法,传入不同的优先级常量,如THREAD_PRIORITY_AUDIO。这可能是更推荐的方式,因为系统API可能封装了底层的细节,并且考虑了兼容性和权限问题。 最后,应该总结注意事项,比如权限限制、不同Android版本的差异,以及系统服务调整的影响。可能还需要提醒用户,不当的设置可能导致系统不稳定,需要谨慎操作。</think>### Android音频进程调度等级设置方法 #### 一、调度机制基础 Android基于Linux内核实现进程调度,音频进程通常使用实时调度策略以确保低延迟。关键调度策略包括: 1. **SCHED_FIFO**:实时先进先出策略,优先级范围1-99 2. **SCHED_RR**:实时轮转策略,优先级范围1-99 3. **SCHED_OTHER**:标准分时调度策略 音频服务如AAudioService会将client线程设置为实时策略[^1],其优先级设置直接影响音频延迟表现。 #### 二、设置方法实践 ##### 1. Native层设置(C/C++) ```cpp #include <pthread.h> #include <sched.h> void setAudioThreadPriority() { pthread_t this_thread = pthread_self(); struct sched_param params; params.sched_priority = sched_get_priority_max(SCHED_FIFO) - 2; // 设置高优先级 pthread_setschedparam(this_thread, SCHED_FIFO, &params); } ``` 注意:需要`CAP_SYS_NICE`权限或加入`audio`组 ##### 2. Java层设置 ```java android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_AUDIO); // 标准音频线程优先级-16 ``` ##### 3. 系统服务级设置 在系统服务中通过Binder调用: ```cpp status_t err = requestPriority(pid, tid, ANDROID_PRIORITY_AUDIO); // 对应优先级-16[^1] ``` #### 三、优先级对照表 | 优先级类型 | 对应 | 适用范围 | |---------------------|--------|--------------------| | THREAD_PRIORITY_AUDIO | -16 | 普通音频线程 | | MAX_REAL_TIME_PRIORITY | 99 | 最高实时优先级 | | MIN_REAL_TIME_PRIORITY | 1 | 最低实时优先级 | #### 四、IO优先级优化 Android 15引入IO优先级调整方案[^2],可配合使用: ```cpp #include <sys/resource.h> setpriority(PRIO_PROCESS, tid, IOPRIO_CLASS_RT); // 设置实时IO优先级 ``` #### 五、注意事项 1. 普通应用无法直接设置实时策略,需系统签名权限 2. Android 8.0+对后台进程调度策略有严格限制 3. 错误设置可能导致系统稳定性问题 4. 不同SoC厂商可能有定制化调度策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值