C Pthread Priority:无法获取预期的行为

C Pthread Priority:无法获取预期的行为,c,linux,pthreads,posix,C,Linux,Pthreads,Posix,在这里,我尝试创建两个线程,为它们分配优先级/策略,并获得预期的行为 预期行为:具有最高优先级的线程(在本例中为thread1)应始终首先执行。 我看到的是:线程输出混合在一起,这意味着没有遵循优先级 代码如下: #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> #include <sched.h> void *thread

在这里,我尝试创建两个线程,为它们分配优先级/策略,并获得预期的行为

预期行为:具有最高优先级的线程(在本例中为thread1)应始终首先执行。 我看到的是:线程输出混合在一起,这意味着没有遵循优先级

代码如下:

#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, &param1);
    pthread_attr_setschedparam(&attr2, &param2);

    pthread_attr_setschedpolicy(&attr1, policy1);
    pthread_attr_setschedpolicy(&attr2, policy2);   

    pthread_attr_getschedparam(&attr1, &param1);
    pthread_attr_getschedparam(&attr2, &param2);

    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;
}
#包括
#包括
#包括
#包括
#包括
void*thread_func1();
void*thread_func2();
int main(){
pthread_t thread1,thread2;
pthread_attr_t attr1、attr2;
结构sched_param param1,param2;
内螺纹1_prio=70;
int thread2_prio=69;
int政策1、政策2;
政策1=附表1;
政策2=附表2;
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);
返回0;
}
void*thread_func1(void*var){
对于(int i=0;i
预期行为:具有最高优先级的线程(在本例中为thread1)应始终首先执行

一般来说,Linux不是这样工作的。底层设计围绕着时间共享,其中任务的优先级影响任务获得的CPU时间百分比,对延迟或抢占没有影响。它只是不打算执行“可以运行的最高优先级任务确实运行(并抢占较低优先级的任务)”就像你想要的

此外:

  • pthread优先级完全被破坏,几乎所有事情都不受支持(除了正常软件不应该使用的实时调度策略,如果您有硬实时需求,可能也不应该使用该策略)

  • nice()
    也会中断,因为它会影响单个线程,而不是像预期的那样影响属于整个进程的所有线程。这种中断意味着您可以(某种程度上)使用
    nice()
    而不是pthread priorities(线程优先级)

  • “优先级”/“尼斯限制”的行为也被打破了(或者至少是过去,我还没有检查它最近是否被修复);在这种情况下,不管限制是什么,你只能降低任务的优先级,而不能将其增加到限制。这完全打破了几种常见的设计(例如。“工作线程从队列中获取作业,然后调整其优先级以适应该作业”和“线程预生成对象供将来使用,然后放入池中,并调整其优先级以满足需求(取决于池的满/空程度)”

最终的结果是(没有极端的麻烦-例如,在内核破损的混乱之上有一个用户空间线程层),通过滥用“SCHED_RR”(加上
nice()
进行不重要/轻微的调整)作为高/中优先级和“SCHED_IDLE”,您实际上可以模拟一个微不足道的“2优先级”系统“作为低优先级


大多数情况下,最好忘记编写正确使用线程优先级的软件(这太难了,不可移植,只提供了它应该提供的部分好处)。当然,这也是潜在的问题(因为大多数软件都不使用线程优先级,所以内核开发人员并不真正关心调度器应该如何工作,也不确定线程优先级,所以大多数软件都不使用线程优先级——这是一个愚蠢的自我永存反馈循环,已经持续了30年).

我修饰了您的程序以检查错误,这一行:

pthread_attr_setschedparam(&attr1, &param1);
无论是否使用root,EINVAL始终失败。快速检查手册表明,在此之前,您必须:

pthread_attr_setinheritsched(&attr1, PTHREAD_EXPLICIT_SCHED);
这仍然不能完全解决问题,更模糊的是,您必须在优先级之前设置策略,因此顺序是:setinheritsched、setChedPolicy、setChedParam

不管您的特定posix操作系统是否对调度参数有用,这都是大家的猜测,但至少这给了它一个战斗的机会

请注意:

  • 为了正确地观察这一点,您需要将线程仿射到单个cpu
  • 您需要使main()的优先级高于任一线程,或者强制线程从一个屏障开始,这样您就可以同时释放它们。否则,您的第一个线程可能会在第二个线程开始之前运行到完成
  • Posix线程属性乱七八糟,您真的想测试它们是否失败。我通常将它们包装在一个类似断言的宏中

  • 通过这些更正和增强,在我的ubuntu 16上,您的程序按预期运行。

    您的每个线程都执行I/O(通过
    printf
    ),几乎所有类型的I/O都会导致线程处于休眠和抢占状态。通常,线程之间的同步使用标准的线程同步原语(信号量、条件变量、互斥体等)。有什么方法可以测试此功能吗?不使用任何线程同步技术。也就是说,完全基于其分配的优先级?可能通过在线程中迭代更多,并比较每个线程写入的行数。线程1是否比线程2写入更多行数并更快完成?我尝试了更多的迭代(100..1000),收到的输出看起来几乎又混在一起了。很难确信thread1的优先级得到了尊重。感谢您的洞察力和解释。我