【Linux】(1)—进程概念-⑤进程调度

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言


提示:以下是本篇文章正文内容,下面案例可供参考

一、Linux进程调度概述

1.1 进程调度的基本概念

进程调度是操作系统决定哪个进程在何时使用CPU资源的过程。Linux作为一个多任务操作系统,需要有效地管理多个进程对CPU的共享访问。

调度器的核心任务

  • 决定哪个进程获得CPU使用权

  • 决定进程占用CPU的时间长度

  • 确保所有进程公平合理地获得CPU资源

  • 保证系统吞吐量和响应时间的平衡

1.2 Linux调度器发展

Linux调度器经历了多个版本的演进:

  • O(n)调度器:早期版本,遍历所有进程选择最优,复杂度高

  • O(1)调度器:2.6内核引入,固定时间选择进程

  • CFS(完全公平调度器):2.6.23后默认调度器,基于红黑树实现

二、Linux进程优先级

2.1 优先级的基本概念

在Linux中,每个进程都有优先级属性,决定了它获得CPU资源的顺序。优先级分为两类:

  1. 普通优先级:100-139(对应nice值-20到19)

  2. 实时优先级:0-99(数值越小优先级越高)

关键字段说明:

  • PRI:进程优先级(Priority)

  • NI:nice值,用于调整优先级

  • PRI(new) = PRI(old) + NI

2.2 nice值与优先级调整

nice值影响进程的优先级,取值范围为-20到19:

  • 负nice值:提高优先级(更可能获得CPU)

  • 正nice值:降低优先级(更少获得CPU)

2.3 优先级调整示例代码

复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>

int main() {
    // 获取当前nice值
    int current = getpriority(PRIO_PROCESS, 0);
    printf("Current nice value: %d\n", current);
    
    // 设置新的nice值
    if (setpriority(PRIO_PROCESS, 0, -5) == -1) {
        perror("setpriority");
        return 1;
    }
    
    printf("New nice value set to -5\n");
    
    // 验证新nice值
    current = getpriority(PRIO_PROCESS, 0);
    printf("Verified nice value: %d\n", current);
    
    return 0;
}
复制代码

三、进程的竞争性与独立性

3.1 进程的竞争性

竞争性指多个进程争夺有限系统资源(特别是CPU资源)的特性:

  • 系统进程数量通常远多于CPU核心数

  • 进程需要竞争CPU时间片来执行

  • 优先级机制确保重要进程优先获得资源

竞争性导致的问题:

  • 资源争用可能导致性能下降

  • 低优先级进程可能"饥饿"(长期得不到资源)

解决方案:

  • 合理的优先级设置

  • 公平的调度算法(如CFS)

  • 进程间的通信与同步机制

3.2 进程的独立性

独立性指进程间相互隔离、互不干扰的特性:

  • 每个进程有独立的地址空间

  • 一个进程崩溃不会影响其他进程

  • 进程间资源默认不共享

独立性的实现机制:

  • 虚拟内存管理

  • 进程隔离技术

  • 权限控制

独立性的好处:

  • 提高系统稳定性

  • 增强安全性

  • 简化程序设计

四、并行与并发

4.1 基本概念

  • 并行(Parallelism)

    • 真正的同时执行

    • 需要多核/多CPU支持

    • 多个进程/线程在不同CPU核心上同时运行

  • 并发(Concurrency)

    • 逻辑上的同时执行

    • 单核CPU通过快速切换实现

    • 多个进程/线程交替使用CPU

4.2 Linux中的并行与并发实现

并行的实现:
复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid1 = fork();
    if (pid1 == 0) {
        // 子进程1
        printf("Child 1 running on core ?\n");
        while(1); // 无限循环
    }
    
    pid_t pid2 = fork();
    if (pid2 == 0) {
        // 子进程2
        printf("Child 2 running on core ?\n");
        while(1); // 无限循环
    }
    
    // 父进程等待
    wait(NULL);
    wait(NULL);
    return 0;
}

使用taskset可以绑定进程到特定CPU核心:

并发的实现:
复制代码
#include <stdio.h>
#include <pthread.h>

void* thread_func(void* arg) {
    int id = *(int*)arg;
    for (int i = 0; i < 5; i++) {
        printf("Thread %d: %d\n", id, i);
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t t1, t2;
    int id1 = 1, id2 = 2;
    
    pthread_create(&t1, NULL, thread_func, &id1);
    pthread_create(&t2, NULL, thread_func, &id2);
    
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    
    return 0;
}

4.3 并行与并发的对比

特性 并行 并发
执行方式 物理上同时执行 逻辑上同时执行
硬件要求 需要多核/多CPU 单核即可实现
实现机制 多进程/多线程分布在多个核心上 时间片轮转快速切换
性能影响 真正提高吞吐量 提高响应性和资源利用率
典型应用 科学计算、批量处理 Web服务器、GUI应用

五、Linux O(1)调度算法

5.1 O(1)调度器架构

Linux 2.6内核引入了O(1)调度器,其主要特点:

  • 固定时间复杂度:无论进程数量多少,选择下一个进程的时间恒定

  • 双队列结构:活动队列和过期队列

  • 优先级数组:每个优先级一个队列

关键数据结构:

复制代码
struct runqueue {
    struct prio_array *active;    // 活动队列
    struct prio_array *expired;   // 过期队列
    // ...其他字段...
};

struct prio_array {
    unsigned int nr_active;       // 活动进程数
    unsigned long bitmap[5];      // 优先级位图
    struct list_head queue[140];  // 优先级队列
};

5.2 O(1)调度过程

  1. 选择下一个进程

    • 从active队列的位图中找到第一个非空队列

    • 从该优先级队列中取出第一个进程

  2. 时间片处理

    • 进程用完时间片后移到expired队列

    • 当active队列为空时,交换active和expired队列

  3. 优先级调整

    • 交互式进程优先级自动提升

    • CPU密集型进程优先级自动降低

5.3 O(1)调度器的优势

  • 高效:选择进程时间与系统负载无关

  • 公平:确保所有进程都有机会执行

  • 响应快:交互式进程能快速获得CPU

  • 可扩展:适应从嵌入式系统到服务器的各种场景

六、实际应用建议

  1. 服务器调优

    • 关键服务设置较高优先级(负nice值)

    • 批处理作业设置较低优先级(正nice值)

    • 考虑使用taskset绑定CPU核心

  2. 多线程编程

    • CPU密集型任务考虑使用多进程实现真正并行

    • I/O密集型任务适合使用多线程实现高并发

    • 注意避免优先级反转问题

  3. 调试工具

    • top/htop:实时查看进程优先级和CPU使用

    • perf:分析程序性能瓶颈

    • strace:跟踪系统调用

  4. 最佳实践

    • 避免频繁修改进程优先级

    • 合理设置进程nice值范围(-10到10)

    • 考虑使用cgroups进行更精细的资源控制

结语

Linux进程调度是一个复杂而精妙的系统,理解其工作原理对于开发高性能应用程序至关重要。通过本文,我们深入探讨了:

  1. Linux进程优先级机制及nice值的调整方法

  2. 进程的竞争性与独立性特性及其实现原理

  3. 并行与并发的区别及在Linux中的实现方式

  4. O(1)调度算法的高效设计思想

掌握这些知识,开发者可以更好地优化程序性能,合理管理系统资源,构建更高效稳定的Linux应用。在实际开发中,应当根据应用特点选择合适的并发模型和优先级设置,以达到最佳的性能表现。

相关推荐
apocelipes38 分钟前
Linux c 运行时获取动态库所在路径
linux·c语言·linux编程
努力学习的小廉1 小时前
深入了解linux系统—— 进程池
linux·运维·服务器
秃头菜狗2 小时前
各个主要目录的功能 / Linux 常见指令
linux·运维·服务器
2301_793102492 小时前
Linux——MySql数据库
linux·数据库
jiunian_cn3 小时前
【Linux】centos软件安装
linux·运维·centos
藥瓿亭3 小时前
K8S认证|CKS题库+答案| 6. 创建 Secret
运维·ubuntu·docker·云原生·容器·kubernetes·cks
程序员JerrySUN3 小时前
[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
java·linux·架构
孤寂大仙v3 小时前
【计算机网络】非阻塞IO——select实现多路转接
linux·计算机网络
2302_809798323 小时前
【JavaWeb】Docker项目部署
java·运维·后端·青少年编程·docker·容器
嵌入式大圣3 小时前
Neko虚拟浏览器远程协作方案:Docker+内网穿透技术部署实践
运维·docker·容器