C Pthread 优先级:无法获得预期的行为
C Pthread Priority : Unable to get expected behavior
在这里,我尝试创建两个线程,将 priorities/policies 分配给它们并获得预期的行为。
预期行为:具有最高优先级的线程(在本例中为线程 1)应始终首先执行。
我所看到的:线程输出混合在一起,这意味着没有遵循优先级。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
void *thread_func1 ();
void *thread_func2 ();
int main (){
pthread_t thread1, thread2;
pthread_attr_t attr1, attr2;
struct sched_param param1, param2;
int thread1_prio = 70;
int thread2_prio = 69;
int policy1, policy2;
policy1 = SCHED_RR;
policy2 = SCHED_RR;
pthread_attr_init(&attr1);
pthread_attr_init(&attr2);
param1.sched_priority = thread1_prio;
param2.sched_priority = thread2_prio;
pthread_attr_setschedparam(&attr1, ¶m1);
pthread_attr_setschedparam(&attr2, ¶m2);
pthread_attr_setschedpolicy(&attr1, policy1);
pthread_attr_setschedpolicy(&attr2, policy2);
pthread_attr_getschedparam(&attr1, ¶m1);
pthread_attr_getschedparam(&attr2, ¶m2);
pthread_attr_getschedpolicy(&attr1, &policy1);
pthread_attr_getschedpolicy(&attr2, &policy2);
pthread_create(&thread1, &attr1, thread_func1, NULL);
pthread_create(&thread2, &attr2, thread_func2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void *thread_func1 (void *var){
for (int i = 0; i<5; i++){
printf("Thread: 1\n");
}
return 0;
}
void *thread_func2 (void *var){
for (int i=0; i<5; i++){
printf("Thread: 2\n");
}
return 0;
}
- 我也尝试过使用
pthread_setschedprio
,仍然无法得到预期的结果。
- 正在执行程序
root
在 post 提出这个问题之前,我确实尝试遵循许多 posts / 示例,但最终变得更加困惑。任何帮助表示赞赏。
编辑:这不是一个真正的问题吗?我的意思是,如果post这个是愚蠢的,请纠正我,并且值得投反对票,因为你们中的一些人已经投了反对票post?
Expected behavior: Thread which has highest priority (in this case, thread1) should execute first always.
一般来说,Linux 不是那样的。底层设计围绕时间共享展开,其中任务的优先级会影响任务获得的 CPU 时间的百分比,并且对延迟或抢占没有影响。它根本不打算像你想要的那样做 "highest priority task that can run does run (and preempts lower priority tasks)"。
另外:
pthread 优先级完全被破坏,几乎所有东西都不支持(除了实时调度策略,普通软件不应该使用它,如果你有困难,可能不应该使用它)实时要求)。
nice()
也被破坏了,因为它会影响单个线程,而不是像预期的那样影响属于整个进程的所有线程。这种破碎意味着如果你勇敢的话,你可以(有点)使用 nice()
而不是 pthread 优先级。
"priority"/nice 限制的行为(或者至少是,我最近没有检查它是否已修复)也被破坏了;因为无论限制是多少,您都只能降低任务的优先级,而不能将其增加到限制。这完全打破了几种常见的设计(例如 "worker thread/s get a job from a queue then adjusts its priority to suit that job" 和 "thread pre-generates objects for future use and puts then in a pool, and adjusts its priority to meet demand (depending on how full/empty the pool is)")。
最终结果是(没有极端的麻烦——例如,在内核损坏的混乱之上的用户-space 线程层)你有效地保留了模拟微不足道的“2 优先级”系统的能力通过滥用 "SCHED_RR"(加上 nice()
进行 insignificant/minor 调整)作为 high/medium 优先级和 "SCHED_IDLE" 作为低优先级。
大部分;最好忘记编写正确使用线程优先级的软件(这太难了,不可移植并且只提供了它应有的部分好处)。当然这也是潜在的问题(因为大多数软件不使用线程优先级,所以内核开发人员不太关心了解调度程序应该如何工作并且不修复线程优先级,所以大多数软件不使用线程优先级 - 这是一个自我延续的白痴反馈循环,现在已经持续了 3 年)。
我修饰了你的程序来检查错误,这一行:
pthread_attr_setschedparam(&attr1, ¶m1);
EINVAL 一直失败,无论是否为 root。快速查看手册,表明在此之前,您必须:
pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
还是没有完全解决,更难理解的是必须在优先级之前设置策略,所以顺序是:setinheritsched、setschedpolicy、setschedparam。
你的特定 posix-OS 是否对调度参数做了任何有用的事情是任何人的猜测,但至少这给了它一个战斗的机会。
一些注意事项:
- 要正确观察这一点,您需要将线程仿射到单个 cpu。
- 您要么需要使 main() 的优先级高于任何一个线程,要么强制线程在屏障处启动,以便您可以同时释放它们。否则,您的第一个线程可能会在第二个线程开始之前 运行 完成。
- Posix 线程属性乱七八糟,真想测试一下是否失败。我通常将它们包装在类似断言的宏中。
通过这些更正和改进,在我的 ubuntu 16 上,您的程序可以按预期运行。
在这里,我尝试创建两个线程,将 priorities/policies 分配给它们并获得预期的行为。
预期行为:具有最高优先级的线程(在本例中为线程 1)应始终首先执行。 我所看到的:线程输出混合在一起,这意味着没有遵循优先级。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
void *thread_func1 ();
void *thread_func2 ();
int main (){
pthread_t thread1, thread2;
pthread_attr_t attr1, attr2;
struct sched_param param1, param2;
int thread1_prio = 70;
int thread2_prio = 69;
int policy1, policy2;
policy1 = SCHED_RR;
policy2 = SCHED_RR;
pthread_attr_init(&attr1);
pthread_attr_init(&attr2);
param1.sched_priority = thread1_prio;
param2.sched_priority = thread2_prio;
pthread_attr_setschedparam(&attr1, ¶m1);
pthread_attr_setschedparam(&attr2, ¶m2);
pthread_attr_setschedpolicy(&attr1, policy1);
pthread_attr_setschedpolicy(&attr2, policy2);
pthread_attr_getschedparam(&attr1, ¶m1);
pthread_attr_getschedparam(&attr2, ¶m2);
pthread_attr_getschedpolicy(&attr1, &policy1);
pthread_attr_getschedpolicy(&attr2, &policy2);
pthread_create(&thread1, &attr1, thread_func1, NULL);
pthread_create(&thread2, &attr2, thread_func2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void *thread_func1 (void *var){
for (int i = 0; i<5; i++){
printf("Thread: 1\n");
}
return 0;
}
void *thread_func2 (void *var){
for (int i=0; i<5; i++){
printf("Thread: 2\n");
}
return 0;
}
- 我也尝试过使用
pthread_setschedprio
,仍然无法得到预期的结果。 - 正在执行程序
root
在 post 提出这个问题之前,我确实尝试遵循许多 posts / 示例,但最终变得更加困惑。任何帮助表示赞赏。
编辑:这不是一个真正的问题吗?我的意思是,如果post这个是愚蠢的,请纠正我,并且值得投反对票,因为你们中的一些人已经投了反对票post?
Expected behavior: Thread which has highest priority (in this case, thread1) should execute first always.
一般来说,Linux 不是那样的。底层设计围绕时间共享展开,其中任务的优先级会影响任务获得的 CPU 时间的百分比,并且对延迟或抢占没有影响。它根本不打算像你想要的那样做 "highest priority task that can run does run (and preempts lower priority tasks)"。
另外:
pthread 优先级完全被破坏,几乎所有东西都不支持(除了实时调度策略,普通软件不应该使用它,如果你有困难,可能不应该使用它)实时要求)。
nice()
也被破坏了,因为它会影响单个线程,而不是像预期的那样影响属于整个进程的所有线程。这种破碎意味着如果你勇敢的话,你可以(有点)使用nice()
而不是 pthread 优先级。"priority"/nice 限制的行为(或者至少是,我最近没有检查它是否已修复)也被破坏了;因为无论限制是多少,您都只能降低任务的优先级,而不能将其增加到限制。这完全打破了几种常见的设计(例如 "worker thread/s get a job from a queue then adjusts its priority to suit that job" 和 "thread pre-generates objects for future use and puts then in a pool, and adjusts its priority to meet demand (depending on how full/empty the pool is)")。
最终结果是(没有极端的麻烦——例如,在内核损坏的混乱之上的用户-space 线程层)你有效地保留了模拟微不足道的“2 优先级”系统的能力通过滥用 "SCHED_RR"(加上 nice()
进行 insignificant/minor 调整)作为 high/medium 优先级和 "SCHED_IDLE" 作为低优先级。
大部分;最好忘记编写正确使用线程优先级的软件(这太难了,不可移植并且只提供了它应有的部分好处)。当然这也是潜在的问题(因为大多数软件不使用线程优先级,所以内核开发人员不太关心了解调度程序应该如何工作并且不修复线程优先级,所以大多数软件不使用线程优先级 - 这是一个自我延续的白痴反馈循环,现在已经持续了 3 年)。
我修饰了你的程序来检查错误,这一行:
pthread_attr_setschedparam(&attr1, ¶m1);
EINVAL 一直失败,无论是否为 root。快速查看手册,表明在此之前,您必须:
pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
还是没有完全解决,更难理解的是必须在优先级之前设置策略,所以顺序是:setinheritsched、setschedpolicy、setschedparam。
你的特定 posix-OS 是否对调度参数做了任何有用的事情是任何人的猜测,但至少这给了它一个战斗的机会。
一些注意事项:
- 要正确观察这一点,您需要将线程仿射到单个 cpu。
- 您要么需要使 main() 的优先级高于任何一个线程,要么强制线程在屏障处启动,以便您可以同时释放它们。否则,您的第一个线程可能会在第二个线程开始之前 运行 完成。
- Posix 线程属性乱七八糟,真想测试一下是否失败。我通常将它们包装在类似断言的宏中。
通过这些更正和改进,在我的 ubuntu 16 上,您的程序可以按预期运行。