【问题标题】:Does SCHED_IDLE actually preclude execution on non-idle core?SCHED_IDLE 实际上是否会阻止在非空闲内核上执行?
【发布时间】:2019-08-23 00:06:53
【问题描述】:

我正在尝试使用SCHED_IDLE 在没有优先级继承互斥体的情况下实现无限制优先级反转的非特权测试用例。该测试适用于 SCHED_FIFO 和不同的实时优先级(非 PI 互斥锁死锁,立即使用 PI 互斥锁解决),但要将其包含在无需实时权限运行的测试集中,我想改用 SCHED_IDLE ,“中”和“高”优先级线程都是SCHED_OTHER(在这种情况下,它并不是真正的优先级“反转”,但这个概念应该仍然有效——“中”线程应该排除“低”线程的执行)。

很遗憾,该测试无法区分 PI 和非 PI 互斥体;无论哪种方式,它都会取得进展。显然,即使有另一个可运行的任务,SCHED_IDLE 任务也在运行。 CPU 亲和性已设置为将它们全部绑定到同一个内核,这样低优先级的任务就不能迁移到不同的内核运行。而且我知道SCHED_IDLE 任务应该在内核空间中以提升的权限运行以防止内核空间优先级反转,所以我尝试通过使其忙循环来确保“低”线程不会进入内核空间用户空间,strace 没有表明它在不应该向前推进的时间内进行系统调用。

Linux 的SCHED_IDLE 是否只允许在内核实际上不空闲时运行空闲任务?或者还有什么我可能会遗漏的东西?

这里是测试代码,稍作修改以便可以在实时模式或SCHED_IDLE 下运行:

#define _GNU_SOURCE
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <semaphore.h>

sem_t sem;

void *start1(void *p)
{
    pthread_mutex_lock(p);
    sem_post(&sem);
    sem_post(&sem);
    usleep(100000);
    pthread_mutex_unlock(p);
    return 0;
}

void *start2(void *p)
{
    sem_wait(&sem);
    time_t t0 = time(0);
    while (pthread_mutex_trylock(p)) {
        if (time(0)>t0+5) return 0;
    }
    pthread_mutex_unlock(p);
    return 0;
}

void *start3(void *p)
{
    sem_wait(&sem);
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    ts.tv_sec += 5;
    int r;
    if (r=pthread_mutex_timedlock(p, &ts)) {
        printf("failed: %d %s\n", r, strerror(r));
    } else {
        pthread_mutex_unlock(p);
    }
    return 0;
}

int main(int argc, char **argv)
{
    int policy = argc>1 ? SCHED_IDLE : SCHED_FIFO;
    int a = sched_get_priority_min(policy);
    pthread_attr_t attr;
    pthread_t t1,t2,t3;
    struct sched_param param = {0};

    cpu_set_t set = {0};
    CPU_ZERO(&set);
    CPU_SET(0, &set);
    pthread_setaffinity_np(pthread_self(), sizeof set, &set);

    pthread_attr_init(&attr);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    pthread_attr_setschedpolicy(&attr, policy);

    pthread_mutexattr_t ma;
    pthread_mutexattr_init(&ma);
    pthread_mutexattr_setprotocol(&ma, PTHREAD_PRIO_INHERIT);
    pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK);
    pthread_mutex_t mtx;
    pthread_mutex_init(&mtx, &ma);

    sem_init(&sem, 0, 0);

    param.sched_priority = a+1;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t2, policy==SCHED_IDLE ? 0 : &attr, start2, &mtx)) return 1;

    param.sched_priority = a+2;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t3, policy==SCHED_IDLE ? 0 : &attr, start3, &mtx)) return 1;

    param.sched_priority = a;
    pthread_attr_setschedparam(&attr, &param);
    if (pthread_create(&t1, &attr, start1, &mtx)) return 1;

    pthread_join(t1, 0);
    pthread_join(t2, 0);
    pthread_join(t3, 0);
    return 0;
}

【问题讨论】:

  • 你能附上你的SCHED_IDLE / SCHED_OTHER PI 测试代码吗?
  • @caf:完成。我将两个版本都压缩成一个程序,所以希望我没有在这个过程中搞砸任何事情。

标签: c linux pthreads posix priority-inversion


【解决方案1】:

Linux 的SCHED_IDLE 是否只允许空闲任务在内核运行时运行 是不是真的闲着?或者还有什么我可能会遗漏的东西?

这是正确的。 SCHED_IDLE 提供任务 a very low but non-zero weighting - CPU 时间比一个不错的 19 任务少 70%。

【讨论】:

  • 谢谢。这使得它不仅对我的测试目的毫无意义,而且对其预期目的也毫无意义:确保降级的任务永远从任何正常任务中占用 cpu 时间。
  • 我相信这个想法是,如果你想要像“从不”这样的保证,你可以使用实时策略。
  • SCHED_RR 运行系统上的所有内容? SCHED_IDLE 应该解决的问题是你想要一个“低于一切”的优先级,而不必明确地使“一切”实时/高于空闲。
  • 我想知道这是否真的可能......让init 在prio 10 或其他时间以SCHED_RR 开始所有内容,并让想要降低优先级的进程降低...大概没有特权也可以降到更低?
  • 嗯,我更多考虑的是,如果你有这样的要求,那往往是因为你有一组已知的任务,你永远不想被打断。对于其他所有事情,您最多可能会在大约 340 个周期中因“空闲”任务而失去 1 个这一事实似乎不是问题。它可能应该被称为SCHED_NICEST 或其他东西;)
猜你喜欢
  • 2011-12-03
  • 2019-11-29
  • 2017-10-12
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
  • 2016-07-19
  • 1970-01-01
  • 2013-03-27
相关资源
最近更新 更多