使用实时优先级的 pthreads

7
我需要管理一个具有不同优先级的线程池,因此我编写了以下线程启动过程:
static
int startup(thrd_t *thrd, thrd_sync_t *sync, int prio)
{
    pthread_attr_t attr;
    int err;
    struct sched_param param = {
        .sched_priority = prio
    };

    assert(pthread_attr_init(&attr) == 0);
    assert(pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0);
    assert(pthread_attr_setschedparam(&attr, &param) == 0);
    err = pthread_create(&thrd->handler, &attr, thread_routine, (void *)thrd);
    pthread_attr_destroy(&attr);

    return err;
}

原则上,非特权用户不应该被允许执行此代码:由于使用高优先级运行线程的安全隐患,pthread_create()调用应返回EPERM。
出乎意料的是,普通用户可以正常工作,但根本不尊重给定的优先级。
我试图通过删除pthread_attr_t并在创建线程后设置调度属性来修改代码:
static
int startup(thrd_t *thrd, thrd_sync_t *sync, int prio)
{
    pthread_attr_t attr;
    int err;
    struct sched_param param = {
        .sched_priority = prio
    };

    err = pthread_create(&thrd->handler, NULL /*&attr*/, thread_routine,
                         (void *)thrd);
    if (err != 0) return err;

    err = pthread_setschedparam(thrd->handler, SCHED_FIFO, &param);
    if (err != 0) return err;

    return err;
}

顺便说一下,这种方法更难管理,因为如果出现错误,我需要杀死新创建的线程。至少在权限要求方面似乎可以正常工作(只有root可以执行此操作),但仍然不尊重优先级。
我做错了什么吗?
编辑
我刚刚添加了以下代码片段,每个线程都会执行:
static
void getinfo ()
{
    struct sched_param param;
    int policy;

    sched_getparam(0, &param);
    DEBUG_FMT("Priority of this process: %d", param.sched_priority);

    pthread_getschedparam(pthread_self(), &policy, &param);

    DEBUG_FMT("Priority of the thread: %d, current policy is: %d and should be %d",
              param.sched_priority, policy, SCHED_FIFO);
}

使用第一种方法(即pthread_attr_t方法),发现pthread_attr_setschedpolicy完全无效,因为优先级为0且策略不是SCHED_FIFO。
使用第二种方法(即pthread_setschedparam方法),函数输出了预期数据,但执行结果仍然错误。

1
你如何确定调用没有被执行?我遇到过类似的情况,但是API根本没有被实现,因此失败了。 - Ioan
@Ioan:请查看问题的更新版本。 - Dacav
2
提示:不要将代码放在 “assert()” 内。如果使用禁用 assert 的编译方式编译,该代码将不会被执行。 - bstpierre
@bstpierre:真的吗?谢谢你提供这个信息!我以前在我的代码中经常这样做,特别是为了检查malloc()返回的不是NULL!看来现在是时候对我所有的库进行硬修复了,我欠你一杯啤酒! - Dacav
1
如果定义了NDEBUG,则assert(x)是一个空操作。 - bstpierre
1个回答

9
我认为您还需要使用pthread_attr_setinheritsched来确保您对优先级设置的更改得到考虑。从手册中可以看出:

PTHREAD_INHERIT_SCHED 指定调度策略和相关属性应继承自创建线程,并且此attr参数中的调度属性将被忽略。

PTHREAD_EXPLICIT_SCHED 指定调度策略和相关属性应设置为来自此属性对象的相应值。

在手册的稍后部分,您会发现:

新初始化的线程属性对象中继承调度器属性的默认设置为PTHREAD_INHERIT_SCHED。


成功了!非常感谢:这解决了两个问题中的一个。但是这相当反直觉:如果我指定了优先级,那么很可能是因为我希望您使用它,对吧? :) 现在我要找出错误行为的原因:也许是一个 bug? - Dacav
@Dacav:你能详细说明一下你的第二个问题吗?我不确定我是否理解了。在那个领域中出现错误(但是你自己的错误;-))的可能性非常小。你没有说太多关于你正在运行的系统,但现在线程实现每天都经过了数十亿次的充分测试。 - Jens Gustedt
目前我的程序只是一个框架:真正的业务逻辑将在以后添加。为了测试优先级,每个线程都会等待条件变量,然后进行广播。然后每个线程都会在stderr上写入虚假信息。我期望的是在低优先级线程之前观察高优先级线程的虚假信息。我怀疑我的双核处理器会导致意外的交错...我正在考虑一个好的测试方法。 - Dacav
哈哈,现在我明白了:)说“可能是个bug”时,我的意思是“也许是我的代码中的bug”。我通常认为库代码是正确的:) - Dacav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接