私が取り組んでいるプロジェクトのために、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
、それともその機能はその環境に残されていますか?
私はこの問題に行き詰まっており、正しい方向への洞察や指針をいただければ幸いです。
ありがとうございます。コードや説明が不明な場合はお知らせください。