c++ - 带有 SCHED_OTHER 的可移植 pthread_setschedparam

标签 c++ linux multithreading unix pthreads

我正在为我正在进行的项目组装一个 Unix/Linux 半可移植线程类(即使用 pthread 库)。部分项目需要能够设置某些线程的优先级,让同一进程中的其他线程有更多的CPU时间;这就是 pthread_setschedparam 函数发挥作用的地方,而我的类(class)却碰壁了。

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

#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 下设置线程的优先级,还是该功能留给所述环境?

我在这个问题上陷入僵局,非常感谢任何正确方向的见解或指示。

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

最佳答案

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

谢谢

关于c++ - 带有 SCHED_OTHER 的可移植 pthread_setschedparam,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10693942/

相关文章:

c++ - std::pow 的性能 - 缓存未命中?

linux - Grep 带空格的单词

cocoa - NSThread 出现 _NSAutoreleaseNoPool 错误

c++ - RH Linux 互斥锁调试

c++ - 从 python 使用 Opencv Cuda 函数

c++ - 高负荷下的c++线程 worker 失败

c++ - iostream 到 zlib 和 C++ 文件?

java - Netty 4 从客户端创建多个连接

c++ - 我怎样才能阻止 gcc 在较新的 ARM cpu 上发出 swap{b}?

java - 同步块(synchronized block)中的代码