首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linux SCHED_FIFO不尊重线程优先级

Linux SCHED_FIFO不尊重线程优先级
EN

Stack Overflow用户
提问于 2020-08-31 16:21:02
回答 1查看 733关注 0票数 1

场景

我已经创建了三个线程,它们固定在单核上,在SCHED_FIFO下具有以下优先级

  1. mainsched_priority = 99
  2. thread_1sched_priority = 97
  3. thread_2sched_priority = 98

工作线程(thread_1thread_2)计算50,000,000素数(~ 10s)之和。它们直到结束时才阻止或执行系统调用(以打印输出)。

主线程休眠一秒钟,然后检查工作线程的承诺是否完成。

预期行为

主线程处于最高优先级。根据赛德

一个SCHED_FIFO线程运行,直到它被I/O请求阻塞,它被一个更高优先级的线程抢占,或者它调用sched_yield(2)。

因此,Main应该在第二次间隔内打印(checking ...)。它是最优先的,所以应该抢先任何运行。当它休眠时,它是阻塞的,所以其他线程应该运行。

  • thread_1:首先完成,因为当不忙时,它有优先权。
  • thread_2:最后完成,只有在thread_1完全完成之后才开始。

实际行为

线程以预期的相反顺序结束:

代码语言:javascript
复制
Thread 1 summed 3001134 primes at priority level: 97
Thread 2 summed 3001134 primes at priority level: 98
Main: Checking ...
Main: Task 1 has finished!
Main: Task 2 has finished!
Main: Exiting at priority level: 99

颠倒优先级顺序,使产生的结果与以前完全相同。

再生产

  1. g++ -o <exec_name> <file_name>.cpp -pthread编译程序
  2. 运行:sudo taskset --cpu-list 1 ./<exec_name>

我的内核是5.4.0-42-generic,我的发行版(如果重要的话)是:Ubuntu 18.04.5 LTS。我做了,而不是,安装了preempt-rt修补程序。

类似问题

  • 我发现问题似乎描述了同样的问题,但没有给出答案。
  • 我还在这个问题中读到,我的高优先级线程可以被抢占,但我不关心这一点,只要它不能被来自同一个进程的其他线程抢占。关于这种情况是否可能发生,我没有足够的信息。

示例代码

代码语言:javascript
复制
#include <thread>
#include <mutex>
#include <iostream>
#include <chrono>
#include <cstring>
#include <future>
#include <pthread.h>
#include <math.h>

// IO Access mutex
std::mutex g_mutex_io;

// Computation function (busy work)
static bool isPrime (unsigned int value)
{
    unsigned int i, root;
    if (value == 1)       return false;
    if (value == 2)       return true;
    if ((value % 2) == 0) return false;
    root = (int)(1.0 + sqrt(value));
    for (i = 3; (i < root) && (value % i != 0); i += 2);
    return (i < root ? false : true);
}

// Thread function
void foo (unsigned int id, unsigned int count)
{
    sched_param sch;
    int policy, sum = 0;

    // Get information about thread
    pthread_getschedparam(pthread_self(), &policy, &sch);

    // Compute primes
    for (unsigned int i = 1; i < count; ++i) {
        sum += (isPrime(i) ? 1 : 0);
    }

    // Print
    {
        std::lock_guard<std::mutex> lock(g_mutex_io);
        std::cout << "Thread " << id << " summed " << sum << " primes"
                  << " at priority level: " << sch.sched_priority << std::endl; 
    }

}

int main ()
{
    sched_param sch;
    int policy;

    // Declare and init task objects
    std::packaged_task<void(unsigned int, unsigned int)> task_1(foo);
    std::packaged_task<void(unsigned int, unsigned int)> task_2(foo);

    // Get the futures
    auto task_fut_1 = task_1.get_future();
    auto task_fut_2 = task_2.get_future();

    // Declare and init thread objects
    std::thread thread_1(std::move(task_1), 1, 50000000);
    std::thread thread_2(std::move(task_2), 2, 50000000);

    // Set first thread policy
    pthread_getschedparam(thread_1.native_handle(), &policy, &sch);
    sch.sched_priority = 97;
    if (pthread_setschedparam(thread_1.native_handle(), SCHED_FIFO, &sch)) {
        std::cerr << "pthread_setschedparam: " << std::strerror(errno) 
                  << std::endl;
        return -1;
    }

    // Set second thread policy
    pthread_getschedparam(thread_2.native_handle(), &policy, &sch);
    sch.sched_priority = 98;
    if (pthread_setschedparam(thread_2.native_handle(), SCHED_FIFO, &sch)) {
        std::cerr << "pthread_setschedparam: " << std::strerror(errno) 
                  << std::endl;
        return -1;
    }

    // Set main process thread priority
    pthread_getschedparam(pthread_self(), &policy, &sch);
    sch.sched_priority = 99;
    if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sch)) {
        std::cerr << "pthread_setschedparam: " << std::strerror(errno)
                  << std::endl;
        return -1;
    }

    // Detach these threads
    thread_1.detach(); thread_2.detach();

    // Check their status with a timeout
    for (int finished = 0; finished < 2; ) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        {
            std::lock_guard<std::mutex> lock(g_mutex_io);
            std::cout << "Main: Checking ..." << std::endl;
        }
        if (task_fut_1.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
            {
                std::lock_guard<std::mutex> lock(g_mutex_io);
                std::cout << "Main: Task 1 has finished!" << std::endl;
            }
            finished++;
        }
        if (task_fut_2.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
            {
                std::lock_guard<std::mutex> lock(g_mutex_io);
                std::cout << "Main: Task 2 has finished!" << std::endl;
            }
            finished++;
        }
    }
    pthread_getschedparam(pthread_self(), &policy, &sch);
    std::cout << "Main: Exiting at priority level: " << sch.sched_priority << std::endl;
    return 0;
}

实验

使用两个核sudo taskset --cpu-list 1,2运行这个程序会产生以下奇怪的输出:

代码语言:javascript
复制
Thread 2 computed 3001134 primes at priority level: 98
Thread 1 computed 3001134 primes at priority level: 0
Main: Checking ...
Main: Task 1 has finished!
Main: Task 2 has finished!
Main: Exiting at priority level: 99

thread_1的优先级为零。

如果我将其扩展到包括三个核心sudo taskset --cpu-list 1,2,3,那么我就得到了我希望在单核上实现的行为:

代码语言:javascript
复制
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Main: Checking ...
Thread 2 computed 3001134 primes at priority level: 98
Thread 1 computed 3001134 primes at priority level: 0
Main: Checking ...
Main: Task 1 has finished!
Main: Task 2 has finished!
Main: Exiting at priority level: 99

重新安排优先级配置的顺序,以便先完成主线程,而不改变原始场景中的输出。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-31 17:46:11

当启动这两个线程时

代码语言:javascript
复制
// Declare and init thread objects
std::thread thread_1(std::move(task_1), 1, 50000000);
std::thread thread_2(std::move(task_2), 2, 50000000);

他们可能(!)立即运行并获取计划参数

代码语言:javascript
复制
// Get information about thread
pthread_getschedparam(pthread_self(), &policy, &sch);

甚至在您使用pthread_setschedparam()将它们设置为另一个值之前。如果两个线程都有相应的调度,输出甚至可能显示0和0。

子线程可以(!)两者都是在主线程设置了优先级之后进行调度的。然后,您将得到预期的输出。但任何结果都是可能的。

当您将pthread_getschedparam()移动到输出之前线程的末尾时,您更有可能得到预期的97和98的输出。但是,即使这样,这两个线程都可以运行到结束,甚至在主线程计划设置优先级之前。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63674522

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档