在 Linux 上以 root 身份调用 SCHED_FIFO 线程的 pthread_create() 时获取 EPERM

问题描述 投票:0回答:5

我试图在 Linux 系统上以 SCHED_FIFO 或 SCHED_RR 策略作为 root 生成线程,但我对 pthread_create() 的调用返回 1 (EPERM)。 pthread_create() 的手册页指出,EPERM 指示“调用者没有适当的权限来设置所需的调度参数或调度策略”。 root 不应该能够指定 SCHED_FIFO 或 SCHED_RR 吗?

我已经将创建线程的代码剥离到一个仅执行此操作的小程序中。它对我来说看起来是正确的,但仍然出现错误。我做错了什么?

节目:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

static void *_Thread(void *arg)
{
    (void)arg;
    printf("Thread running!\n");
    return NULL;
}

int main(void)
{
    int retVal;
    pthread_attr_t attr;
    struct sched_param schedParam;
    pthread_t thread;

    retVal = pthread_attr_init(&attr);
    if (retVal)
    {
        fprintf(stderr, "pthread_attr_init error %d\n", retVal);
        exit(1);
    }

    retVal = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    if (retVal)
    {
        fprintf(stderr, "pthread_attr_setinheritsched error %d\n", retVal);
        exit(1);
    }

    retVal = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    if (retVal)
    {
        fprintf(stderr, "pthread_attr_setschedpolicy error %d\n", retVal);
        exit(1);
    }

    schedParam.sched_priority = 1;
    retVal = pthread_attr_setschedparam(&attr, &schedParam);
    if (retVal)
    {
        fprintf(stderr, "pthread_attr_setschedparam error %d\n", retVal);
        exit(1);
    }

    retVal = pthread_create(&thread,
                            &attr,
                            _Thread,
                            NULL);
    if (retVal)
    {
        fprintf(stderr, "pthread_create error %d\n", retVal);
        exit(1);
    }

    retVal = pthread_join(thread, NULL);
    if (retVal)
    {
        fprintf(stderr, "pthread_join error %d\n", retVal);
        exit(1);
    }

    printf("main run successfully\n");
    return 0;
}

该程序已编译并以 root 身份运行。运行时,它在调用 pthread_create 时程序失败,返回 EPERM。

将线程更改为 SCHED_RR 调度没有任何效果 - EPERM 仍由 pthread_create 返回。

将线程改为SCHED_OTHER调度,并将其优先级改为0,程序就可以正常运行了。

c pthreads
5个回答
8
投票

一定是你的实时优先级软限制太严格了。

在运行代码之前在 shell 中调用

ulimit -r unlimited
。或者直接在代码中调用
setrlimit(RLIMIT_RTPRIO, ...)

系统范围的限制在

/etc/security/limits.conf
中设置。


8
投票

令人惊讶的是,差不多10年后我遇到了与OP相同的问题:CentOS 7.6,生成一个实时线程,root用户,ulimit -r说“无限制”,但线程创建失败返回EPERM。原来失败是由Linux内核中的以下子句引起的:

kernel/sched/core.c

          if (user) {
  #ifdef CONFIG_RT_GROUP_SCHED
                  /*
                   * Do not allow realtime tasks into groups that have
no runtime
                   * assigned.
                   */
                  if (rt_bandwidth_enabled() && rt_policy(policy) &&
                                  task_group(p)->rt_bandwidth.rt_runtime == 0 &&
                                  !task_group_is_autogroup(task_group(p))) {
                              task_rq_unlock(rq, p, &flags);
                              return -EPERM;
                  }
  #endif

鉴于此,Linux cgroup 文档 https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt 和 CONFIG_RT_GROUP_SCHED 文档 https://www.kernel.org/doc/Documentation/ Scheduler/sched-rt-group.txt,通过将当前 shell 添加到现有的带有实时调度信息的 cgroup 来解决问题:

cd /sys/fs/cgroup/cpu
echo $$ > tasks

然后运行可执行文件,从当前 shell 生成实时线程,线程创建成功。


1
投票

我已经在 Linux(2.6 内核)、Solaris 9 和 10 上测试了您的代码。没有问题。这与您的实时优先级设置有关。您可以通过以下方式更改:

ulimit -r unlimited

哎呀。马克西姆已经带着答案来了......


1
投票

以 root 用户身份运行程序。因为我们搞乱了调度(针对 FIFO 和 RR)。你也(暗示)搞乱了相对优先级,而只有 root 才能做到。

正常运行上面的程序,pthread_create()返回EPERM,但作为root用户可以正常工作。

有关更多信息,请访问:http://www.linuxforums.org/forum/programming-scripting/111359-pthread-error.html


0
投票

在 CentOS 7 上遇到过这个。将 /proc/sys/kernel/sched_rt_runtime_us 设置为 -1 后,就可以了。

© www.soinside.com 2019 - 2024. All rights reserved.