线程优先级不能可靠暴露调度不确定性,因其实际效果受调度器策略、系统负载和竞争条件影响;需通过实时调度策略、多线程竞争和延迟分布分析来观测真实不确定性。

线程优先级本身不能可靠暴露调度不确定性
操作系统对 setpriority、pthread_setschedparam 或 Windows 的 SetThreadPriority 的响应,不等于实际 CPU 调度行为。Linux 默认的 CFS 调度器会弱化静态优先级的影响,Windows 的优先级提升也受前台进程组、I/O 等因素干扰。你设了高优先级,不代表它真能“插队”——尤其在负载低、无竞争时,所有线程都可能被公平执行,根本看不出差异。
想观察不确定性,得制造可观测的竞争条件:
- 至少启动 2 个以上计算密集型线程(比如忙循环或浮点累加),且核心数 ≤ 线程数
- 禁用 CPU 亲和性(避免绑定到固定核,否则掩盖跨核调度抖动)
- 用
clock_gettime(CLOCK_MONOTONIC, &ts)记录每轮关键操作的时间戳,而非依赖sleep或打印延时 - 运行时间足够长(≥5秒),采集数百次调度间隔样本
Linux 下用 SCHED_FIFO + chrt 观察硬实时调度抖动
普通 SCHED_OTHER 优先级在用户态几乎不可控;要放大不确定性,必须切入实时类调度策略。但注意:SCHED_FIFO 需 root 权限,且不当使用会导致系统无响应。
实操步骤:
- 用
chrt -f 50 ./a.out启动高优先级实时线程(50 是中等实时优先级,1–99 可用) - 另一线程用
chrt -f 10启动低优先级实时线程 - 两线程各自执行固定次数的
getrusage(RUSAGE_SELF, &ru)+ 忙等待,记录每次循环耗时 - 对比两者耗时标准差:高优线程波动小,低优线程在高优抢占下会出现 >1ms 的延迟尖峰
这种抖动不是“bug”,而是 CFS 为公平性让出 CPU、实时调度器又强制抢占共同导致的边界行为。
为什么 pthread_priority 不影响 pthread_cond_wait 唤醒顺序
线程优先级只作用于“就绪态→运行态”的调度决策,而 pthread_cond_wait 把线程挂起进等待队列,此时优先级信息已丢失。当 pthread_cond_signal 触发时,唤醒顺序由 futex 内部链表决定(通常是 FIFO),与优先级无关。
若你期望高优线程先被唤醒,必须手动控制:
- 用
pthread_mutex_lock+ 自定义就绪队列(按优先级排序的std::priority_queue) - 唤醒时只通知一个线程,由它检查条件并决定是否继续转发
- 避免多个线程同时
wait在同一个 condvar 上还依赖优先级抢资源
否则你会看到:低优线程先醒来、发现条件不满足、再次 wait;高优线程还在队列尾部——这不是调度器错了,是语义本就不支持。
真正反映不确定性的指标不是优先级,而是调度延迟分布
别盯着 getpriority 返回值或 /proc/[pid]/stat 里的 policy 字段。真正该采集的是:
- 从线程就绪(如
pthread_cond_signal返回)到其run状态的时间(需内核跟踪点或 eBPFtracepoint:sched:sched_wakeup) - 同一进程内多个线程的
sched_stat_runtime在 /proc/[pid]/task/[tid]/sched 中的方差 - 用
perf sched latency抓取真实调度延迟直方图(单位:μs)
你会发现:即使同优先级、同策略,延迟分布也是双峰甚至多峰的——一边是 cache 命中+本地核空闲的快速路径,另一边是 TLB miss+跨 NUMA 迁移+中断抢占的慢路径。这才是不确定性藏身之处。

















