带有SCHED_OTHER的便携式pthread_setschedparam

时间:2012-05-21 23:28:48

标签: c++ linux multithreading unix pthreads

我正在为我正在开发的项目组建一个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下设置线程的优先级,或者该功能是否留给所述环境?

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

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

1 个答案:

答案 0 :(得分:1)

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

由于