当前位置: 首页 > article >正文

Linux系统编程之线程优先级

概述

        在Linux系统中,线程优先级是影响多线程应用程序性能和响应速度的关键因素之一。通过合理设置线程优先级,可以确保关键任务得到及时处理,同时避免低优先级任务过度占用系统资源。

        线程优先级是指操作系统根据一定的规则分配给每个线程的一个数值,用于决定该线程获得CPU时间的顺序和频率。一般来说,优先级越高,线程越有可能被调度执行。相反,优先级较低的线程则需要等待高优先级线程完成之后才能获得CPU时间。然而,这并不意味着低优先级线程永远不会被执行,而是它们的执行机会相对较少。

优先级范围

        Linux支持多种线程调度策略,在每种策略下,线程都有其特定的优先级范围。下面,我们将介绍几种常见的调度策略。

        1、先入先出(SCHED_FIFO)。一种实时调度策略,适用于对延迟敏感的应用程序。一旦线程开始运行,它会一直占用CPU直到主动放弃或完成任务,不受其他同优先级线程的影响。其优先级范围为1到99,数字越大表示优先级越高。

        2、轮转调度(SCHED_RR)。类似于SCHED_FIFO,但为每个线程分配了一个固定的时间片。当一个线程用完其时间片后,即使没有完成工作也会被暂停,让位于下一个同优先级的线程。其优先级范围同样为1到99,数字越大表示优先级越高。

        3、完全公平调度器(SCHED_OTHER)。Linux默认的非实时调度策略,适用于大多数普通应用。基于虚拟运行时间来衡量每个线程应当获得多少CPU时间,保证所有线程都能公平地获得CPU资源。其优先级范围为-20到19,可通过nice值调整,默认值为0。nice值越小,优先级越高;nice值越大,优先级越低。

        4、批处理调度和低优先级调度(SCHED_BATCH和SCHED_IDLE)。这两个调度策略主要用于后台批处理作业或低优先级服务,其优先级范围通常不需要显式设置。

设置线程优先级

        pthread_setschedparam函数用于设置线程调度参数,允许我们指定线程的调度策略和优先级。其函数原型如下。

int pthread_setschedparam(pthread_t thread, int policy, 
    const struct sched_param *param);

        各个参数和返回值的含义如下。

        thread:表示要修改调度参数的线程,可通过pthread_self函数获取当前线程的ID,也可使用其他方式获取特定线程的ID。

        policy:指定线程的调度策略,可取值包括上面介绍的SCHED_FIFO、SCHED_RR、SCHED_OTHER、SCHED_BATCH、SCHED_IDLE。

        param:指向struct sched_param类型的指针,包含线程的调度参数。其主要成员是sched_priority,它定义了线程的优先级。如前所述,对于不同的调度策略,优先级的有效范围也不同。

        返回值:成功时返回0,失败时可通过errno获取具体的错误代码。常见的错误代码为:EINVAL(调度策略无效或优先级超出允许范围)、EPERM(没有足够的权限)、ESRCH(没有找到对应的线程)。

        在下面的示例代码中,我们创建了两个线程:一个由主线程设置优先级,另一个在其自身的线程函数内设置优先级。主线程创建external_priority_thread线程后,立即设置其为实时优先级30,并执行简单的工作循环。internal_priority_thread线程启动后,自行将其优先级提升至50,并执行类似的工作循环。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

// 在线程外部(主线程中)设置优先级
void* external_priority_thread(void* arg)
{
    for (int i = 0; i < 5; ++i)
    {
        printf("External-priority thread working... %d\n", i);
        sleep(1);
    }

    return NULL;
}

// 在线程内部设置优先级
void* internal_priority_thread(void* arg)
{
    // 获取当前线程的调度策略和优先级
    int policy = 0;
    struct sched_param param;
    pthread_getschedparam(pthread_self(), &policy, &param);
    printf("Internal-priority thread initial priority: %d\n", param.sched_priority);

    // 尝试设置新的高优先级
    param.sched_priority = 50;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);

    for (int i = 0; i < 5; ++i)
    {
        printf("Internal-priority thread working... %d\n", i);
        sleep(1);
    }

    return NULL;
}

int main()
{
    // 创建线程,在线程外部(主线程中)设置优先级
    pthread_t ext_prio_thread;
    struct sched_param param = { .sched_priority = 30 };
    pthread_create(&ext_prio_thread, NULL, external_priority_thread, NULL);
    pthread_setschedparam(ext_prio_thread, SCHED_FIFO, &param);

    // 创建线程,在线程内部设置优先级
    pthread_t int_prio_thread;
    pthread_create(&int_prio_thread, NULL, internal_priority_thread, NULL);

    // 等待两个线程完成
    pthread_join(ext_prio_thread, NULL);
    pthread_join(int_prio_thread, NULL);
    printf("Both threads have completed\n");
    return 0;
}

注意事项

        1、确保设置的优先级在所选调度策略的有效范围内,超出范围可能会导致EINVAL错误。

        2、对于实时调度策略(比如:SCHED_FIFO或SCHED_RR),可能需要超级用户权限才能成功设置线程优先级。普通用户创建的线程默认采用SCHED_OTHER策略,并且其优先级受到限制。

        3、高优先级线程会抢占低优先级线程的CPU时间,可能导致系统饥饿现象。因此,在设定优先级时,应当谨慎权衡各个线程的重要性。

        4、在某些情况下,可以根据应用程序的状态来动态调整线程优先级。比如:当检测到系统负载过高时,适当降低一些非关键线程的优先级,以释放更多资源给更重要的任务。


http://www.kler.cn/a/502372.html

相关文章:

  • 通过Apache、Nginx限制直接访问public下的静态文件
  • C++ ——— 内部类
  • 六十九:基于openssl实战验证RSA
  • JAVA安全编码规范
  • 开源模型应用落地-qwen2-7b-instruct-LoRA微调合并-ms-swift-单机单卡-V100(十三)
  • 景联文科技提供高质量多模态数据处理服务,驱动AI新时代
  • LeetCode1170 比较字符串最小字母出现频次
  • C++ 鼠标轨迹算法 - 防止游戏检测
  • Kafka——两种集群搭建详解 k8s
  • C#格式化输出
  • 世优波塔数字人 AI 大屏再升级:让智能展厅讲解触手可及
  • 【Apache Doris】周FAQ集锦:第 29 期
  • VS Code 中,GitLens 和 Git Graph
  • 【大数据】Apache Superset:可视化开源架构
  • 如何更轻松的对React refs 的理解?都有哪些应用场景?
  • [Qt] 窗口 | 菜单栏MenuBar
  • springboot基于安卓的反诈APP
  • 代码随想录算法【Day20】
  • 【yum 无法使用】centos7 配置阿里云的 CentOS 镜像源
  • 解析OVN架构及其在OpenStack中的集成
  • 【前端】自学基础算法 -- 20.图的深度优先搜索
  • 【Uniapp-Vue3】pages.json页面路由globalStyle的属性
  • C++开源项目 VLC 源代码的交叉编译以及库的裁剪方法详解
  • MySQL(高级特性篇) 01 章——Linux下MySQL的安装与使用
  • 平均(2023-省赛-贪心)
  • MySql怎么查看连接池是否打满