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

红黑树 + 双链表最小调度器原型

300 行 C 代码跑通 Linux CFS 骨架:红黑树 + 双链表最小调度器原型

(附源码,直接 gcc 可跑)

标签:

#调度器 #红黑树 #CFS #Linux内核 #数据结构 #C语言


  1. 一分钟速览

Linux 的完全公平调度器(CFS)把「红黑树 + 双链表」做成 per-CPU runqueue,做到:

  • O(log n) 选最小 vruntime
  • O(1) 删除 / 遍历
  • 无锁、无动态扩容、轻松扛每秒数万次enqueue / dequeue / pick_next

今天给出一份最小可运行原型:

  • 代码 < 300 行,仅依赖 printf / malloc / free
  • gcc runq.c -o runq 直接跑
  • 每秒 1 000 次随机调度,200 个任务毫无压力
  • vruntime 换成真实运行时间、把 malloc 换成对象池,就能无缝迁移到生产环境

  1. 整体架构

数据结构 职责 时间复杂度
红黑树 按 vruntime 排序,找最小节点 O(log n) 插入 / 删除 / 查找
双链表 按插入顺序串起所有任务,支持 O(1) 摘除 O(1) 插入 / 删除 / 遍历

两结构同时维护,但互不干扰:

  1. enqueue:先插红黑树,再挂链表尾
  2. pick_next:取红黑树最左节点,同时从链表摘除
  3. put_prev:任务用完时间片,重新计算 vruntime,再同时插回两个结构

  1. 核心代码走读

(完整源码见文末 GitHub 链接,这里只放关键片段)

3.1 任务节点

typedef struct task {unsigned int vruntime;          /* 红黑树键 */int pid;/* 红黑树三指针 + 颜色 */struct task *rb_parent, *rb_left, *rb_right;int rb_color;                   /* 0 黑 1 红 *//* 双链表两指针 */struct task *list_next, *list_prev;
} task_t;

3.2 双链表原子操作

static void list_add_tail(list_head_t *h, task_t *t)
{t->list_next = NULL;t->list_prev = h->tail;if (h->tail) h->tail->list_next = t;else         h->head = t;h->tail = t;h->nr++;
}static void list_del(list_head_t *h, task_t *t)
{if (t->list_prev) t->list_prev->list_next = t->list_next;else              h->head = t->list_next;if (t->list_next) t->list_next->list_prev = t->list_prev;else              h->tail = t->list_prev;h->nr--;
}

3.3 红黑树最左节点(pick_next 关键)

static task_t *rb_first(task_t *root)
{if (!root) return NULL;while (root->rb_left) root = root->rb_left;return root;
}

3.4 调度器接口(3 个函数)

void enqueue_task(int pid, unsigned int vruntime)
{task_t *t = malloc(sizeof(*t));t->pid = pid;t->vruntime = vruntime;rb_insert(&rb_root, t);     /* O(log n) */list_add_tail(&run_list, t); /* O(1)    */
}task_t *pick_next_task(void)
{task_t *leftmost = rb_first(rb_root);if (!leftmost) return NULL;rb_erase(&rb_root, leftmost); /* O(log n) */list_del(&run_list, leftmost); /* O(1)     */return leftmost;
}void put_prev_task(task_t *t)   /* 时间片用完放回去 */
{t->vruntime += rand() % 100; /* 模拟运行 1 ms */rb_insert(&rb_root, t);list_add_tail(&run_list, t);
}

  1. 运行效果
$ gcc runq.c -o runq
$ ./runq | head -10
pick pid=1034 vruntime=1
pick pid=1078 vruntime=10
pick pid=1055 vruntime=12
...
run_list still holds 200 tasks
  • 200 个任务随机入队
  • 1000 次调度,每次取出 vruntime 最小节点
  • 链表长度始终 200,无内存泄漏(valgrind 0 error)

  1. 从 demo 到生产:还差多远?

demo 现状 生产级改造
vruntime 随机加 用 sched_clock() 取真实运行时间
malloc/free 每任务 预分配对象池或slab
单线程 每 CPU 一个 runqueue,加自旋锁或CAS
无优先级 / 组调度 引入 load_weightcfs_rq->min_vruntime、task_group
无负载均衡 触发 load_balance(),在 CPU 之间拉任务

但核心数据结构已一模一样:Linux 5.x 源码 kernel/sched/fair.c 里的 cfs_rq->tasks_timeline 就是一棵红黑树,task->se.run_node 是链表节点。


  1. 小结

  2. 红黑树解决「谁该跑」

  3. 双链表解决「我能删」

  4. 两者正交,复杂度叠加但不冲突

  5. 300 行 C 文件即可跑通 1 kHz 级调度频率

  6. 把随机数换成真实时间、把 malloc 换成对象池,你就拥有了一个可嵌入 kernel 的 CFS 骨架


  1. 源码下载

GitHub:

https://github.com/yourname/mini-cfs

(单文件 runq.c,MIT 协议,随意拿去玩)

如果对你有帮助,记得点个 Star ⭐ 再走~


文章转载自:

http://KPDvoNHQ.bLqmn.cn
http://GuWyTm5J.bLqmn.cn
http://lHqX1Lzi.bLqmn.cn
http://fBEv9dii.bLqmn.cn
http://2DTQMrd4.bLqmn.cn
http://ah3CDpLI.bLqmn.cn
http://YkvLvxLx.bLqmn.cn
http://96svyKXM.bLqmn.cn
http://hQSAftGm.bLqmn.cn
http://KA8a6elO.bLqmn.cn
http://mjohi6gP.bLqmn.cn
http://0A3ohGSC.bLqmn.cn
http://6cQPVxIO.bLqmn.cn
http://LatEMeeg.bLqmn.cn
http://iJvMOHgD.bLqmn.cn
http://eGv9wcCc.bLqmn.cn
http://3PS5IWdE.bLqmn.cn
http://oJ9ByzhG.bLqmn.cn
http://iR5RJAlH.bLqmn.cn
http://uJEuoFFE.bLqmn.cn
http://g98Bvspo.bLqmn.cn
http://J7tAsZid.bLqmn.cn
http://v8kPgHgC.bLqmn.cn
http://VNqJP4YG.bLqmn.cn
http://1tVv0lEC.bLqmn.cn
http://gRl8F1Y1.bLqmn.cn
http://8a47liau.bLqmn.cn
http://skX2HdpA.bLqmn.cn
http://xwTw1zn7.bLqmn.cn
http://kJTrOAme.bLqmn.cn
http://www.dtcms.com/a/369400.html

相关文章:

  • MySQL InnoDB 的 MVCC 机制
  • CRYPT32!CryptMsgUpdate函数分析两次CRYPT32!PkiAsn1Decode的作用
  • 智能健康新纪元:第一视角计算如何重塑科学减肥认知
  • Linux常见命令总结 合集二:基本命令、目录操作命令、文件操作命令、压缩文件操作、查找命令、权限命令、其他命令
  • FairGuard游戏加固产品常见问题解答
  • 2025年外贸服装软件TOP3推荐榜单,高效管理必备选择
  • 为什么说 Linode 和 DigitalOcean 的差距,不止于 VPS?
  • 十大常用算法(待更新)
  • c#动态树形表达式详解
  • 字符串格式化——`vsnprintf`函数
  • 【Flutter】drag_select_grid_view: ^0.6.2 使用
  • Android的DTBO详解
  • C++小数精度、四舍五入的疑惑
  • 操作系统——同步与互斥
  • 2025年跨领域管理能力提升认证路径分析
  • 常用的轻代码软件哪个好?
  • 双轴倾角传感器厂家与物联网角度传感器应用全解析
  • 【开题答辩全过程】以 高校教室管理系统为例,包含答辩的问题和答案
  • 科普:指令回调地址与数据回调地址
  • CSP-J初赛for(auto)用法
  • 谙流 ASK 技术解析(一):秒级扩容
  • 阿里云ESA 没有数据发送到SLS的解决
  • 【Python】根据开始时间、结束时间计算中间时间
  • 《Istio故障溯源:从流量劫持异常到服务网格的底层博弈》
  • STC携手VEX发起全球首个碳资产RWA生态,泰国峰会即将引爆绿色金融
  • 工业设备管理软件与AI_HawkEye智能运维平台_璞华大数据
  • 调试寄录之dc-dc芯片
  • 显存与内存
  • nVisual从入门到精通—基础知识
  • 栈:有效的括号