3

私が取り組んでいるプロジェクトのために、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_FIFOまたは優先クラスを「想定」しSCHED_RRて最小/最大値を取得しようとしましたが、これにより有効な最小/最大値が得られ、「無効な引数」エラーは発生しませんが、関数ループ出力は優先順位付けされていません代わりに、関数がたまたま呼び出された順序になります (優先度が設定されていない場合に予想されます)。

理想的には、現在のプロセスの優先度クラスを取得し、そのクラスにもスレッドを割り当てますが、現在のプロセスの優先度がSCHED_OTHERそれに基づいてスレッドを設定している場合、望ましくない無効な結果が生成されます。

スレッドの優先順位を設定したり、有効な最小/最大値を取得したりするための、より「移植可能な」方法はありますか? 特定の環境でスレッドの優先度を設定することもできますかSCHED_OTHER、それともその機能はその環境に残されていますか?

私はこの問題に行き詰まっており、正しい方向への洞察や指針をいただければ幸いです。

ありがとうございます。コードや説明が不明な場合はお知らせください。

4

1 に答える 1

2

理解を深めるのに役立つ場合は、これを参照してください。しかし、私が学んだことはほとんどありません.SCHED_OTHERは、すべての非リアルタイムスレッドが同じ優先度を持つことを意味する唯一のものです. しかし、質問では、BSD は SCHED_OTHER の場合でも最大値と最小値を 0 と 99 に指定し、その理由を理解していませんでしたが、1 つのことは明らかです。その場合、範囲が [0-0] の場合のように、nice (nice でスレッドの優先度を修正できる場合はお知らせください) を使用して優先度を設定するなど、特別な処理を行うとはるかにうまくいきます。

ありがとう

于 2012-05-22T01:25:43.963 に答える