使用 pthread 调度策略和优先级没有任何区别

Posted

技术标签:

【中文标题】使用 pthread 调度策略和优先级没有任何区别【英文标题】:Scheduling policy and priority using pthread does not make any difference 【发布时间】:2021-12-25 06:54:38 【问题描述】:

我正在使用 pthread 运行一个简单的多线程程序。考虑使用实时调度程序(SCHED_FIFO 策略),低优先级线程将无法运行,直到高优先级线程完成。但是,当我同时运行这个程序的两个版本(唯一的区别是优先级 99->1)时,它们几乎同时完成。我什至将策略更改为 SCHED_OTHER,但仍然没有区别。

# include <stdio.h>
# include <string.h>
# include <pthread.h>
# include <stdlib.h>
# include <unistd.h>
# include <math.h>

# define NUM_THREADS    128

pthread_t tid[NUM_THREADS];
int indexes[NUM_THREADS];

void* dummyThread(void *arg)

    unsigned long i = 0;
    pthread_t id = pthread_self();
    float a, b = 5, c = 8;

    printf("Thread %d started.\n", *(int*)arg + 1);

    for(i = 0; i < 10000000; i++)
        a = sin(b) + sqrt(b);
    
    printf("Thread %d finished.\n", *(int*)arg + 1);

    return NULL;


int main(void)

    int i = 0;
    pthread_attr_t attr;
    struct sched_param schedParam;
    struct timespec start, finish;
    double elapsed;

    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    schedParam.sched_priority = 1;
    pthread_attr_setschedparam(&attr, &schedParam);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    clock_gettime(CLOCK_MONOTONIC, &start);

    for (i = 0 ; i < NUM_THREADS; i++)
    
        indexes[i] = i;

        if (!pthread_create((void*)&tid[i], &attr, &dummyThread, &indexes[i]))
            printf("Thread %d created successfully.\n", i + 1);
        
        else
            printf("Failed to create Thread %d.\n", i + 1);
    

    for (i = 0 ; i < NUM_THREADS; i++)
        pthread_join(tid[i], NULL);

    clock_gettime(CLOCK_MONOTONIC, &finish);
    elapsed = (finish.tv_sec - start.tv_sec);
    elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
    printf("%lf\n", elapsed);

    return 0;

编辑 1:通过添加 pthread_attr_setschedparam 和错误检查更新了我的代码。在没有 sudo 的情况下运行它时我没有收到任何错误,并且更改优先级或调度策略仍然不会改变结果。

编辑 2:我注意到当我在同一进程中创建具有不同优先级的线程时,它运行良好。在下面的代码中,对于偶数索引的线程,我分配优先级 1,而对于奇数索引的线程,我分配优先级 99。它运行良好,奇数线程在偶数线程之前先完成。

# include <stdio.h>
# include <string.h>
# include <pthread.h>
# include <stdlib.h>
# include <unistd.h>
# include <math.h>

# define NUM_THREADS    128

pthread_t tid[NUM_THREADS];
int indexes[NUM_THREADS];

void* dummyThread(void *arg)

    unsigned long i = 0;
    pthread_t id = pthread_self();
    float a, b = 5, c = 8;

    printf("Thread %d started.\n", *(int*)arg);

    for(i = 0; i < 10000000; i++)
        a = sin(b) + sqrt(b);
    
    printf("Thread %d finished.\n", *(int*)arg);

    return NULL;


int main(void)

    int i = 0;
    pthread_attr_t attr;
    struct sched_param schedParam;
    struct timespec start, finish;
    double elapsed;

    clock_gettime(CLOCK_MONOTONIC, &start);

    for (i = 0 ; i < NUM_THREADS; i++)
    
        indexes[i] = i;

        pthread_attr_init(&attr);
        pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
        schedParam.sched_priority = i % 2 == 0 ? 1 : 99;
        pthread_attr_setschedparam(&attr, &schedParam);
        pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

        if (!pthread_create((void*)&tid[i], &attr, &dummyThread, &indexes[i]))
            printf("Thread %d created successfully.\n", i);
        
        else
            printf("Failed to create Thread %d.\n", i);
    

    for (i = 0 ; i < NUM_THREADS; i++)
        pthread_join(tid[i], NULL);

    clock_gettime(CLOCK_MONOTONIC, &finish);
    elapsed = (finish.tv_sec - start.tv_sec);
    elapsed += (finish.tv_nsec - start.tv_nsec) / 1000000000.0;
    printf("%lf\n", elapsed);

    return 0;

由于来自不同进程的线程都被发送到内核中的同一个调度程序,我不知道为什么它不适用于不同的进程。

【问题讨论】:

为什么会有任何不同? N 个核心有 X 量的工作要做。改变优先级并不会改变这一点。 您需要做的第一件事是检查所有pthread_..函数是否有错误返回。除非您以 root 的身份运行二进制文件,否则您的 pthread_attr_setschedparam 可能会失败。 @MartinJames 是的,工作量是一样的。但是当所有 CPU 内核都被占用时,调度程序会优先考虑具有更高优先级的线程。如果它们在并行运行时共享相同数量的 CPU 时间,优先级是什么? @EmployedRussian 是的,我已经检查过了。没有错误,它们运行正常。我已经简化了上面的代码,但是我在创建线程时会检查错误,并且在线程中还有 printf 语句以确保它们正常运行。 【参考方案1】:

来自男人pthread_attr_setschedpolicy

为了使政策设置由 pthread_attr_setschedpolicy() 在调用时生效 pthread_create(3),调用者必须使用 pthread_attr_setinheritsched(3) 设置继承调度程序 属性对象 attr 的属性 PTHREAD_EXPLICIT_SCHED。

你忽略了这样做,所以你的SCHED_FIFO 没有任何效果。

一旦我添加了pthread_attr_setinheritsched(&amp;attr, PTHREAD_EXPLICIT_SCHED); 调用,pthread_create() 就会以EPERM 开始失败(因为只有root 可以创建SCHED_FIFO 线程)。

【讨论】:

这很有趣,因为即使我添加pthread_attr_setinheritsched(&amp;attr, PTHREAD_EXPLICIT_SCHED),我也没有收到任何错误。并且无论是否使用sudo 运行代码,它仍然忽略了优先级和调度程序。 你知道为什么会这样吗? @AmirFakhimBabaei 我没有。也许你在错误的地方添加了pthread_attr_setinheritsched()?我在pthread_attr_setschedparam() 通话后立即添加了它。你检查它是否成功?编辑您的问题并显示确切来源,包括错误检查? 我刚刚更新了我的代码。 @AmirFakhimBabaei 运行你的确切代码给我Failed to create Thread 1. Failed to create Thread 2. ...。您使用的是什么 Linux 和 libc?您是在WSL2 或某种模拟器下运行它吗?如果没有sudo,我看不出这段代码如何工作。

以上是关于使用 pthread 调度策略和优先级没有任何区别的主要内容,如果未能解决你的问题,请参考以下文章

Linux 内核线程调度示例一 ④ ( pthread_attr_init 初始化线程属性对象 | 完整代码示例 )

Linux 内核线程调度示例一 ④ ( pthread_attr_init 初始化线程属性对象 | 完整代码示例 )

Linux 内核进程优先级与调度策略 ③ ( 设置获取线程优先级的核心函数 | 修改线程调度策略函数 )

linux命令学习

线程调度策略SCHED_RR(轮转法)和SCHED_FIFO(先进先出)之对照

pthread_setschedparam(设置线程的优先级)