一、時間管理
- 時間片輪轉機制
概述
TencentOS tiny操作系統內核是一個搶佔式內核,搶佔式內核的特點是,如果最高優先級的任務不放棄CPU(調用tos_task_delay、tos_task_yeild等主動放權,或者任務間同步通信機制的pend接口等),那麼CPU將會一直被此任務獨佔。
假設這樣一種場景:系統中包含多個同等優先級的任務,且這幾個任務體中都沒有放棄CPU的行爲,則會出現的情況是,這幾個任務始終只有第一個被得到調度的那個在運行,因爲第一個得到調度的任務體中不會主動放棄CPU,而其他任務優先級上與其相等無法搶佔。此種場景下,其他任務會因得不到CPU而陷入飢餓狀態。
時間片輪轉機制提供了按時間片佔用調度的策略,可以解決上述場景下的任務飢餓問題。
API講解
編程實例
1、在tos_config.h中,配置時間片輪轉組件開關TOS_CFG_ROUND_ROBIN_EN:
#define TOS_CFG_ROUND_ROBIN_EN 1u
2、編寫main.c示例代碼:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "cmsis_os.h"
#include "stdio.h"
#include "tos_k.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define STK_SIZE_TASK_DEMO 512
#define STK_SIZE_TASK_SAMPLE 512
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/*
此代碼中創建了兩個同等優先級(PRIO_TASK_DEMO)的任務task_demo1、task_demo2,兩個任務體中做的操作是不斷對各自的計數器(demo1_counter、demo2_counter)做自增操作(沒有放棄CPU的操作),時間片分別爲timeslice_demo1、timeslice_demo2。
同時創建了一個優先級比task_demo1、task_demo2較高的採樣任務task_sample,此任務不間歇的對兩個計數器進行採樣。在開啓時間片輪轉的情況下,task_demo1、task_demo2得到運行的時間比例應該是timeslice_demo1與timeslice_demo2的比例,那麼demo1_counter和demo2_counter值的比例應該也差不多是timeslice_demo1與timeslice_demo2的比例。
*/
// task_demo1和task_demo2的優先級
#define PRIO_TASK_DEMO 4
// 採樣任務的優先級
#define PRIO_TASK_SAMPLE (PRIO_TASK_DEMO - 1)
// task_demo1的時間片,在tos_task_create時傳入
const k_timeslice_t timeslice_demo1 = 10;
// task_demo2的時間片,在tos_task_create時傳入
const k_timeslice_t timeslice_demo2 = 20;
k_stack_t stack_task_demo1[STK_SIZE_TASK_DEMO];
k_stack_t stack_task_demo2[STK_SIZE_TASK_DEMO];
k_stack_t stack_task_sample[STK_SIZE_TASK_SAMPLE];
k_task_t task_demo1;
k_task_t task_demo2;
k_task_t task_sample;
extern void entry_task_demo1(void *arg);
extern void entry_task_demo2(void *arg);
extern void entry_task_sample(void *arg);
uint64_t demo1_counter = 0;
uint64_t demo2_counter = 0;
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
void entry_task_demo1(void *arg)
{
while (K_TRUE) {
++demo1_counter;
}
}
void entry_task_demo2(void *arg)
{
while (K_TRUE) {
++demo2_counter;
}
}
void entry_task_sample(void *arg)
{
while (K_TRUE) {
++demo2_counter;
printf("demo1_counter: %lld\n", demo1_counter);
printf("demo2_counter: %lld\n", demo2_counter);
printf("demo2_counter / demo1_counter = %f\n",
(double)demo2_counter / demo1_counter);
printf("should almost equals to:\n");
printf("timeslice_demo2 / timeslice_demo1 = %f\n\n", (double)timeslice_demo2 / timeslice_demo1);
tos_task_delay(1000);
}
}
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
tos_knl_init();
// 配置robin機制參數
tos_robin_default_timeslice_config((k_timeslice_t)500u);
(void)tos_task_create(&task_demo1, "demo1", entry_task_demo1, NULL,
PRIO_TASK_DEMO, stack_task_demo1, STK_SIZE_TASK_DEMO,
timeslice_demo1);
(void)tos_task_create(&task_demo2, "demo2", entry_task_demo2, NULL,
PRIO_TASK_DEMO, stack_task_demo2, STK_SIZE_TASK_DEMO,
timeslice_demo2);
(void)tos_task_create(&task_sample, "sample", entry_task_sample, NULL,
PRIO_TASK_SAMPLE, stack_task_sample, STK_SIZE_TASK_SAMPLE,
0);
tos_knl_start();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
3、運行效果
源碼鏈接:Git