带SCHED_OTHER的便携式pthread_setschedparam

portable pthread_setschedparam with SCHED_OTHER

本文关键字:pthread setschedparam 便携式 OTHER SCHED      更新时间:2023-10-16

我正在为我正在处理的项目整理一个Unix/Linux半可移植线程类(即使用pthread库(。项目的一部分需要能够设置某些线程的优先级,以允许同一进程中的其他线程占用更多的 CPU 时间;这就是pthread_setschedparam函数的用武之地,我的班级碰到了一堵砖墙。

以下是我整理的一个简单的测试来说明我的问题:

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sched.h>
#include <string.h>
#include <errno.h>
pthread_mutex_t m_mtx;
bool m_goahead;
void dosleep(int millis)
{
    usleep(millis*1000);
}
void domsg(const char *msg)
{
    pthread_mutex_lock(&m_mtx);
    std::cout << msg << std::endl;
    pthread_mutex_unlock(&m_mtx);
}
void dowait() {
    while (!m_goahead) {
        dosleep(1);
    }
}
void *fn1(void *param)
{
    domsg("in fn1...waiting");
    dowait();
    while (m_goahead) {
        dosleep(1000);
        domsg("in fn1 loop");
    }
}
void *fn2(void *param)
{
    domsg("in fn2...waiting");
    dowait();
    while (m_goahead) {
        dosleep(1000);
        domsg("in fn2 loop");
    }
}
int main(int argc, char **argv)
{
    // min prio = -2, max prio = 2
    int t1_pri = 2, t2_pri = 0, main_pri = 1;
    //SCHED_RR, SCHED_FIFO, SCHED_OTHER (POSIX scheduling policies)
    int sched = SCHED_OTHER; // standard
    // get the range between min and max and set the priorities base on split range
    int min = sched_get_priority_min(sched);
    int max = sched_get_priority_max(sched);
    int skip = (max - min) / 5; // 5 since -2...2
    struct sched_param main_param, t1_param, t2_param;
    memset(&main_param, 0, sizeof(sched_param));
    memset(&t1_param, 0, sizeof(sched_param));
    memset(&t2_param, 0, sizeof(sched_param));
    main_param.sched_priority = (min + ((main_pri+2) * (skip+1))) + (skip / 2);
    t1_param.sched_priority = (min + ((t1_pri+2) * (skip+1))) + (skip / 2);
    t2_param.sched_priority = (min + ((t2_pri+2) * (skip+1))) + (skip / 2);
    std::cout << "main thread will have a prio of " << main_param.sched_priority << std::endl;
    std::cout << "t1 thread will have a prio of " << t1_param.sched_priority << std::endl;
    std::cout << "t2 thread will have a prio of " << t2_param.sched_priority << std::endl;
    m_goahead = false;
    pthread_mutex_init(&m_mtx, NULL);
    pthread_t t1, t2;
    // Create the threads 
    if (pthread_create(&t1, NULL, fn1, NULL) != 0) {
        std::cout << "couldn't create t1" << std::endl;
        return -1;
    }
    if (pthread_create(&t2, NULL, fn2, NULL) != 0) {
        std::cout << "couldn't create t2" << std::endl;
        return -1;
    }
    dosleep(1000); // sleep a second before setting priorities
    // --main thread--
    if (pthread_setschedparam(pthread_self(), sched, &main_param) != 0) {
        std::cout << "error setting priority for main thread: (" << errno << "), " << strerror(errno) << std::endl;
    }
    // --t1 thread--
    if (pthread_setschedparam(t1, sched, &t1_param) != 0) {
        std::cout << "error setting priority for T1: (" << errno << "), " << strerror(errno) << std::endl;
    }
    // --t2 thread--
    if (pthread_setschedparam(t2, sched, &t2_param) != 0) {
        std::cout << "error setting priority for T2: (" << errno << "), " << strerror(errno) << std::endl;
    }
    m_goahead = true; // all start
    // loop until user interupt
    for (;;) {
        dosleep(1000);
        domsg("in main loop");
    }
    pthread_mutex_destroy(&m_mtx);
    return 0;
}

基于这段代码,如果我编译它并在 OpenBSD 系统上运行它,我会得到以下内容:

main thread will have a prio of 24
t1 thread will have a prio of 31
t2 thread will have a prio of 17
in fn1...waiting
in fn2...waiting
in fn1 loop
in main loop
in fn2 loop
in fn1 loop
in main loop
in fn2 loop
in fn1 loop
in main loop
in fn2 loop

请注意它如何按照线程优先级的顺序,fn1,main,fn2...

如果我在 Ubuntu 10.04LTS 系统上运行相同的测试,我会得到以下结果:

main thread will have a prio of 3
t1 thread will have a prio of 4
t2 thread will have a prio of 2
in fn1...waiting
in fn2...waiting
error setting priority for main thread: (22), Invalid argument
error setting priority for T1: (22), Invalid argument
error setting priority for T2: (22), Invalid argument
in main loop
in fn2 loop
in fn1 loop
in main loop
in fn2 loop
in fn1 loop
in main loop
in fn2 loop
in fn1 loop

我知道无效参数是因为我指定了SCHED_OTHER优先级类并尝试为其分配 0 以外的任何数字;我无法弄清楚的是我如何才能使其正常工作?

我尝试"假设"一个SCHED_FIFOSCHED_RR优先级类来获取最小/最大值,这给了我有效的最小/最大值,我没有收到"无效参数"错误,但函数循环输出不是按优先级顺序,而是以函数碰巧被调用的任何顺序(如果未设置优先级,则在预期

(。理想情况下,我会获得当前进程的优先级类,

然后在该类上分配线程,但是,如果当前进程的优先级是SCHED_OTHER则基于该类别设置一个线程,从而产生我不想要的无效结果。

是否有更"可移植"的方式来设置线程的优先级或获取有效的最小/最大值?我甚至可以在某些环境中SCHED_OTHER下设置线程的优先级,还是将该功能留给所述环境?

我在这个问题上陷入僵局,并希望有任何见解或指向正确方向的指示。

谢谢,如果我的代码/解释不清楚,请告诉我。

如果

它有助于增加理解,请参考这个。但我学到的很少,SCHED_OTHER只是意味着所有非实时线程将具有相同的优先级。但是在提到的问题中,BSD给出max和min 0和99,即使在SCHED_OTHER的情况下,也不明白为什么,但有一点很清楚,它不是一个非常便携的,依靠它的确切值将无济于事。在这种情况下,放置特殊处理会做得更好,例如如果范围为 [0-0],则使用 nice(如果线程优先级可以通过 nice 修复,请告诉我(来设置优先级。

谢谢