2012-05-21 5 views
3

Я собираю полупрозрачный класс потоков Unix/Linux (т. Е. Используя библиотеку pthread) для проекта, над которым я работаю. Часть проекта требует возможности установить приоритет определенных потоков, чтобы другие потоки в одном процессе увеличивали время процессора; в который входит функция pthread_setschedparam, и мой класс попадает в кирпичную стену.portable pthread_setschedparam с SCHED_OTHER

Ниже приведен простой тест, который я поставил вместе, чтобы проиллюстрировать мою проблему:

#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; 
} 

Base на этот код, если я компилирую это и запустить его на системе 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, главный, 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_FIFO или SCHED_RR класс приоритета, чтобы получить значения min/max, которые дают мне действительные минимальные/максимальные значения, и я не получаю ошибку «недопустимый аргумент», но цикл функции вывод не находится в приоритетном порядке, вместо этого в любом порядке функция вызвана вызовом (ожидается, если не будет установлен приоритет).

В идеале я бы получил класс приоритетов текущего процесса, а затем назначил поток на этом классе, однако, если приоритет текущего процесса равен SCHED_OTHER, тогда установите поток на основе того, что создает недопустимые результаты, которые я не хочу ,

Есть ли более «портативный» способ установить приоритет потока или получить допустимые значения min/max? Могу ли я установить приоритет потока под SCHED_OTHER в определенных средах или эта функциональность оставлена ​​в указанной среде?

Я нахожусь в тупике с этой проблемой и буду признателен за любые прозрения или указатели в правильном направлении.

Спасибо и, пожалуйста, дайте мне знать, если мой код/​​объяснение неясно.

ответ

1

См. this, если это помогает увеличить понимание. Но то, что мало я узнал, SCHED_OTHER - это их единственное, что означает, что все потоки не реального времени будут иметь равный приоритет. Но тогда в вопросе BSD давали max и min 0 и 99 даже в случае SCHED_OTHER, не понимали почему, но ясно одно, оно не очень портативное и полагаться на его точное значение не поможет. В этом случае установка специальной обработки будет намного лучше, например, если диапазон равен [0-0], то с помощью nice (если приоритет потока может быть исправлен с помощью nice, пожалуйста, дайте мне знать), чтобы установить приоритет.

Thanks

+1

Спасибо за информацию! К сожалению использование 'nice' действует только на процессы, а не на потоки, но из того, что я могу видеть в разных источниках ядра, приоритеты потоков - ОЧЕНЬ зависящие от системы; OpenBSD реализует абсолютный минимальный стандарт POSIX, но имеет более надежный планировщик потоков, в то время как Ubuntu реализует некоторые непереносимые идиомы POSIX и имеет более простой диспетчер потоков, где Solaris реализует политику 'SCHED_OTHER'. Я все еще охочусь за этим. – txtechhelp

Смежные вопросы