Linux调度分析(2)调度用户态API介绍

Linux调度的实现在内核中,但用户态可以通过调度相关的systemcall可以进行调度相关的设置。这些设置包括:

  1. 设置调度策略
    设置调度策略通过系统调用函数sched_setscheduler()实现,它的函数定义如下:
    SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param)
    pid为需要设置的线程pid,policy为需要设置的调度策略,param为设置参数
    Linux调度policy包括:
  • SCHED_NORMAL:普通调度
  • SCHED_FIFO:先进先出调度
  • SCHED_RR:Round-robin调度
  • SCHED_BATCH: ?
  • SCHED_IDLE:idle调度
  • SCHED_DEADLINE: DL调度
  • SCHED_EXT:EBPF调度
  1. 获取调度策略
    获取调度策略通过系统调用函数sched_getscheduler()实现,它的函数定义如下:
    SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)

  2. 设置亲和性
    设置线程的亲和性,可以让线程运行在指定的CPU上,它是通过系统调用sched_setaffinity()实现,它的函数定义如下:
    SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, unsigned long __user *, user_mask_ptr)

  3. 获取亲和性
    获取线程的亲和性可以通过系统调用sched_getaffinity()实现,它的函数定义如下:
    SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, unsigned long __user *, user_mask_ptr)

  4. 放弃当前CPU运行
    系统调用sched_yield()可以让当前运行的线程放弃在当前CPU的运行,切换其他线程运行
    SYSCALL_DEFINE0(sched_yield)

  5. 其他的系统调用
    除了上述系统调用外,还有其他系统调用如:

  • sched_get_priority_max()获取某个调度策略的最大priority值
  • sched_get_priority_min()获取某个调度策略的最小priority值
  • nice()修改当前线程的priority值
  • sched_setparam()/sched_getparam设置/获取线程的priority
  • sched_setattr()/sched_getattr()设置/获取线程的扩展属性
  • sched_rr_get_interval()返回线程默认的slice即调度时间片
  1. 隐式的调度相关的操作
    上述系统调用明确调用了调度相关的系统调用,其实在用户态调用sleep()等函数时隐含着schedule()让当前线程主动让出CPU的调度操作。

下面代码是设置pid为10000的线程调度相关的设置:将其设置为SCHED_FIFO调度策略,获取SCHED_FIFO的最大和最小优先级,设置线程的亲和性(将其绑定到CPU 0),在做了一些循环操作后放弃当前CPU。

`...

static void die(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}

int main(void)
{
int ret;
pid_t pid = 100000; // 100000 means "this process"

/* -----------------------------
 * 1. Set scheduling policy
 * ----------------------------- */

struct sched_param sp;
memset(&sp, 0, sizeof(sp));

// Choose a real-time policy, e.g., SCHED_FIFO or SCHED_RR.
// NOTE: This usually requires root privileges.
int policy = SCHED_FIFO;

// Get allowed priority range for this policy
int max_prio = sched_get_priority_max(policy);
int min_prio = sched_get_priority_min(policy);

if (max_prio == -1 || min_prio == -1) {
    die("sched_get_priority_*");
}

// Use some priority in the valid range; here we just pick the max.
sp.sched_priority = max_prio;

ret = sched_setscheduler(pid, policy, &sp);
if (ret == -1) {
    // If you see EPERM, you likely need to run as root.
    fprintf(stderr,
            "sched_setscheduler failed: %s (need CAP_SYS_NICE/root for RT)\n",
            strerror(errno));
    // Not fatal for demonstration, continue with default policy.
} else {
    printf("Scheduler set to policy %d, priority %d\n", policy,
           sp.sched_priority);
}

/* -----------------------------
 * 2. Set CPU affinity (pin to CPU 0)
 * ----------------------------- */

cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(0, &set);  // bind to CPU 0

ret = sched_setaffinity(pid, sizeof(set), &set);
if (ret == -1) {
    die("sched_setaffinity");
} else {
    printf("Affinity set to CPU 0\n");
}

/* -----------------------------
 * 3. Do some work and yield
 * ----------------------------- */

for (int i = 0; i < 5; ++i) {
    printf("Iteration %d on CPU %d\n", i, sched_getcpu());

    // Do some dummy work
    for (volatile long j = 0; j < 100000000L; ++j)
        ;  // busy loop

    printf("Yielding CPU...\n");
    ret = sched_yield();  // Let other runnable tasks run
    if (ret == -1) {
        die("sched_yield");
    }
}

printf("Done.\n");
return 0;

}`

posted @ 2025-12-30 10:10  耳朵一样  阅读(18)  评论(0)    收藏  举报