You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C中实现Round-Robin调度并避免系统调度干扰?

如何用自定义Round-Robin调度完全替代系统调度器管理进程?

你的核心问题在于:仅用SIGSTOP/SIGCONT无法完全屏蔽系统调度器的干预,原因有两点:一是调度线程优先级不足,可能被目标进程抢占导致切换不及时;二是目标进程默认使用SCHED_OTHER调度策略,系统会根据进程优先级自动调度,即使手动暂停/唤醒,也可能出现不符合预期的调度行为。

要完全接管进程调度,你需要从以下几个方面调整:


关键调整点

  • 重构进程层级:让调度器所在进程作为两个目标进程的父进程,确保对目标进程的控制权限更直接,同时能正确处理子进程状态变化。
  • 初始暂停所有目标进程:创建子进程后立即发送SIGSTOP,让它们处于暂停状态,完全由调度器决定何时唤醒,避免系统调度器自主启动它们。
  • 提升调度器线程优先级:将调度器线程设置为SCHED_FIFO调度策略并赋予高优先级,确保它能在时间片到期时及时抢占当前运行的目标进程,保证切换时机准确。
  • 修改目标进程的调度策略:将目标进程设置为SCHED_FIFO,这样它们被唤醒后会持续运行直到被SIGSTOP暂停,不会被系统调度器主动抢占(除非有更高优先级的进程,比如你的调度器线程)。
  • 使用精确的计时机制:替换轮询式的时间检查为timer_create+信号的方式,既节省CPU资源,又能保证时间片到期时触发切换的准确性。

修改后的示例代码

#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdbool.h>
#include <sched.h>

#define TIME_QUANTUM_MS 2000  // 时间片2秒
pid_t pids[2];
bool current_running = 0;  // 当前运行的进程索引(0或1)
timer_t switch_timer;

// 定时器触发的切换函数
void switch_process(union sigval arg) {
    // 暂停当前进程
    kill(pids[current_running], SIGSTOP);
    printf("[调度器] 暂停进程 %d\n", pids[current_running]);
    
    // 切换到另一个进程
    current_running = !current_running;
    kill(pids[current_running], SIGCONT);
    printf("[调度器] 恢复进程 %d\n", pids[current_running]);
    
    // 重启定时器
    struct itimerspec ts = {
        .it_interval = {0, TIME_QUANTUM_MS * 1000000},  // 重复间隔
        .it_value = {0, TIME_QUANTUM_MS * 1000000}       // 下次触发时间
    };
    timer_settime(switch_timer, 0, &ts, NULL);
}

// 目标进程1的任务
void process1() {
    while(1) {
        printf("进程P1正在运行\n");
        usleep(500000);  // 模拟工作负载
    }
}

// 目标进程2的任务
void process2() {
    while(1) {
        printf("进程P2正在运行\n");
        usleep(500000);  // 模拟工作负载
    }
}

// 初始化调度器定时器
void init_scheduler_timer() {
    struct sigevent sev = {
        .sigev_notify = SIGEV_THREAD,
        .sigev_value.sival_ptr = &switch_timer,
        .sigev_notify_function = switch_process,
        .sigev_notify_attributes = NULL
    };
    
    // 创建定时器
    timer_create(CLOCK_MONOTONIC, &sev, &switch_timer);
    
    // 设置初始触发时间
    struct itimerspec ts = {
        .it_interval = {0, TIME_QUANTUM_MS * 1000000},
        .it_value = {0, TIME_QUANTUM_MS * 1000000}
    };
    timer_settime(switch_timer, 0, &ts, NULL);
}

// 设置线程为高优先级SCHED_FIFO
void set_high_priority(pthread_t thread) {
    struct sched_param param;
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    pthread_setschedparam(thread, SCHED_FIFO, &param);
}

int main(int argc, char *argv[]) {
    // 创建进程P1
    pids[0] = fork();
    if (pids[0] == 0) {
        // 设置P1为SCHED_FIFO调度策略
        struct sched_param param = {.sched_priority = 10};
        sched_setscheduler(0, SCHED_FIFO, &param);
        process1();
        exit(0);
    }
    
    // 创建进程P2
    pids[1] = fork();
    if (pids[1] == 0) {
        // 设置P2为SCHED_FIFO调度策略
        struct sched_param param = {.sched_priority = 10};
        sched_setscheduler(0, SCHED_FIFO, &param);
        process2();
        exit(0);
    }
    
    // 初始暂停两个进程
    kill(pids[0], SIGSTOP);
    kill(pids[1], SIGSTOP);
    printf("[调度器] 初始暂停所有进程\n");
    
    // 创建调度器线程
    pthread_t scheduler_thread;
    pthread_create(&scheduler_thread, NULL, (void *)init_scheduler_timer, NULL);
    
    // 提升调度器线程优先级
    set_high_priority(scheduler_thread);
    
    // 唤醒第一个进程
    kill(pids[current_running], SIGCONT);
    printf("[调度器] 启动第一个进程 %d\n", pids[current_running]);
    
    // 等待子进程结束(实际不会结束,只是防止父进程退出)
    while (wait(NULL) > 0);
    
    return 0;
}

运行注意事项

  1. 需要以root权限运行程序,因为修改进程调度策略和优先级需要CAP_SYS_NICE权限。
  2. 目标进程的SCHED_FIFO优先级要低于调度器线程的优先级(示例中调度器用最高优先级,目标进程用10),确保调度器能及时抢占。
  3. 示例中用CLOCK_MONOTONIC时钟,避免系统时间变化影响计时准确性。

内容的提问来源于stack exchange,提问作者Jgl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 20:10:31