Linux多核系统下线程的调度策略和优先级
1、引言
Linux中,多任务应用程序在单核(并发处理)或多核(并行处理)cpu下运行,出现了不同的表征形式。在多核系统中,由于线程执行处于一个并行执行的状态,任务之间的优先级没有起作用,即高优先级任务未必先于低优先级任务前执行,存在并行执行的可能。本文主要介绍嵌入式Linux(多核)下,实时线程并行执行产生的隐患,并保证了高实时线程先于低实时线程执行。
2、应用程序具体表征现象
本项目以应用程序中的 main_task(A任务) 、ethcat_thread_noblock(B任务) 和 common_server (C任务)三个线程为例进行说明,该三个线程均使用spi接口进行外部通信,且spi接口资源利用信号量进行同步
在系统运行过程中,A任务和B任务均为实时任务(SCHED_FIFO),C任务为非实时任务(SCHED_OTHER),且 A任务的优先级为20,B任务的优先级为68。
1. 系统预期处理流程:
系统任务执行顺序:B > A > C
基于线程调度策略:实时任务先于非实时任务执行
基于实时线程优先级:高优先级任务先于低优先级任务执行
当SPI资源被C任务占据,且A任务和B任务同时进行抢占时,SPI资源会先被B任务获得(优先级高),故 B任务的最大执行时间 = C任务的执行时间 + 系统的抖动时间
2. 系统实际处理流程:
系统任务执行顺序:B/A > C (A任务和B任务运行在不同cpu核上)
实时任务A和B并行执行,满足线程调度策略,不满足优先级策略
当SPI资源被C任务占据,且A任务和B任务同时进行抢占时,SPI资源可能会被A任务占据,故 B任务的最大执行时间 = A任务的执行时间 + C任务的执行时间 + 系统的抖动时间
问题:B任务的最大执行时间为啥被拉长?
猜想:在多核系统下,由于实时任务的优先级策略失效,会导致B任务的最大执行时间被进一步拉长。
在单核CPU情况下,优先级抢占调度是一种常见的调度策略。在多核CPU中,由于有多个任务可以同时在不同的核中运行,优先级在局部发生了变化,有可能发生低优先级的任务先完成的现象。在多核系统中需要重新考虑任务的调度策略。
例如:任务 T1,T2,T3,T4, 优先级为 T4 > T3 > T2 = T1,图示将表示出单核与多核在任务调度时的区别。
从图中表示情况可知:虽然T4的优先级高于T3,但T4并没有像单核CPU中先于T3完成而是基本时间相差不大。
3、举例论证上述猜想
创建 4
个线程: 系统预期处理流程 : 2 > 1 > 3/4
- 线程索引号 1和2:是实时线程(调度策略是 SCHED_FIFO,优先级是 51,52);
- 线程索引号 3和4:是普通线程(调度策略是 SCHED_OTHER);
// arm-linux-gnueabihf-gcc -o multicore multicore_test.c -lpthread
#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <pthread.h>
// 用来打印当前的线程信息:调度策略是什么?优先级是多少?
void get_thread_info(const int thread_index)
{
int policy;
struct sched_param param;
printf("\n====> thread_index = %d \n", thread_index);
pthread_getschedparam(pthread_self(), &policy, ¶m);
if (SCHED_OTHER == policy)
printf("thread_index %d: SCHED_OTHER \n", thread_index);
else if (SCHED_FIFO == policy)
printf("thread_index %d: SCHED_FIFO \n", thread_index);
else if (SCHED_RR == policy)
printf("thread_index %d: SCHED_RR \n", thread_index);
printf("thread_index %d: priority = %d \n"