2023-8-26增 写在前面
这个其实就是一个裸机程序中的一个伪操作系统,他的核心功能只能通过优先级切换任务,不能达到类似多线程的效果,不能实现像真正的操作系统那样按时间片轮询,有独立的堆栈等。所以只是一个稍微强于前后台系统的伪操作系统。同时这里寻找优先级较高的算法也比较粗糙,这里可以参考ucos的优先级调度算法改进
废话不多说,这个操作系统能干什么
可以实现多优先级的任务调度,任务挂起,设定任务运行次数
基本思路,以前基本都是使用前后台程序,每次都是在主循环判断哪个任务触发了,才回去执行,如果多个任务同时触发,那就只能按照顺序依次执行,经过改进之后可以根据优先级选择任务优先级较高的任务先调用,每次将任务链表中的所有没有被挂起的任务全部都执行一遍之后才能进行第二轮任务调度
直接上代码task.h:
#ifndef _TASK_
#define _TASK_
#include <stdio.h>//提供printf调试
#include <malloc.h>//用来提供malloc
//#define NULL 0
typedef struct {
char priority;//任务优先级
char prime_priority;//任务最初优先级,在任务初始化和任务恢复时使用
char end_priority;//记录用户初始化的优先级
int times;//任务调用次数设定值
int times_up;//任务调用次数计数
void (*set_up)(void* node);//调用用户函数前调用初始化系统设置的一个函数钩子
void (*task_hanger)(void);//系统函数钩子
}Node_data;
typedef struct Node_link{
Node_data data;//任务节点数据域
struct Node_link* next;//任务节点的next指针域
}Task_Node;
Task_Node* PNode_Init(void);
//LRtos初始化
void LRtos_init(Task_Node *Plink);
/*创建一个任务
* PNode 任务链表
* priority 任务优先级
* task_function 任务调用的具体函数
* times 任务函数调用次数
* 返回 新建节点的地址
*/
Task_Node* LRtos_TaskCreate(Task_Node* Plink,char priority,void *task_function,char times);
/*任务挂起
* Plink 任务链表
* PNode 任务节点地址
* */
void LRtos_TaskSuspend(Task_Node* PNode);
/*任务恢复*/
void LRtos_TaskResume(Task_Node* PNode);
/*任务删除*/
int LRtos_TaskDel(Task_Node* Plink, Task_Node* PNode);
//开启任务调度
void LRtos_Open(Task_Node* Plink);
#endif // !1
然后是task.c
#include "task.h"
//初始化头结点
Task_Node* PNode_Init(void) {
Task_Node* p;
p = (Task_Node*)malloc(sizeof(Task_Node));
if (!p) return 0;//内存不足分配失败
else {
p->next = NULL;
return p;
}
}
void Task_SetUp(Task_Node* node) {//任务的默认初始化函数
if ((node->data.times != 0) && (node->data.times == node->data.times_up)) {//如果初始设定不是无限次数,并且次数已经达到
node->data.prime_priority = -1;//任务将自己挂起
node->data.priority = -1;
printf("任务将自己挂起\n");
}
else {
node->data.times_up++;
node->data.task_hanger();
}
}
void NULLTaskCallBeak() {
printf("这里是空闲任务\n");
}
void LRtos_init(Task_Node* Plink) {
//创建空闲任务 优先级为0
//Task_Node *NULLTask=
LRtos_TaskCreate(Plink,0, NULLTaskCallBeak,0);
}
Task_Node* LRtos_TaskCreate(Task_Node* Plink, char priority, void* task_function, char times) {
if (Plink == NULL)//检查L是否为空
return 0;//表示传入的L并没有分配空间
Task_Node* p;//新建的节点
Task_Node* q; //用来寻找最后一个节点
q = Plink;
p = (Task_Node*)malloc(sizeof(Task_Node));//创建一个新节点
if (p == NULL) return 0;//创建新节点失败
p->data.priority = priority;//将数据放入数据域
p->data.prime_priority = priority;
p->data.end_priority = priority;
p->data.task_hanger = task_function;
p->data.times = times;
p->data.times_up = 0;
p->data.set_up = Task_SetUp;//设置为默认setup函数
p->next = NULL;//将新建节点的后继指针置空
while (q->next) {//找到最后一个节点
q = q->next;
}
q->next = p;//将新建的节点接在后面
return p;
}
void LRtos_TaskSuspend_SYS(Task_Node* PNode) {//系统调用任务挂起
PNode->data.priority = -1;
}
void LRtos_TaskSuspend(Task_Node* PNode) {//用户调用任务挂起
PNode->data.prime_priority = -1;
PNode->data.priority = -1;
}
void LRtos_TaskResume_SYS(Task_Node* PNode) {//系统调用任务恢复
PNode->data.priority = PNode->data.prime_priority;
}
void LRtos_TaskResume(Task_Node* PNode) {//用户调用任务恢复,这个任务恢复会抢占本轮任务调用
PNode->data.prime_priority = PNode->data.end_priority;
PNode->data.priority = PNode->data.end_priority;
}
/*任务删除*/
int LRtos_TaskDel(Task_Node* Plink, Task_Node* PNode) {
Task_Node* p=Plink,*q;
while (p && !(p->next == PNode))
p = p->next;
if (p == NULL)
return 0;
q = PNode;//保存被删除节点的地址
p->next = q->next;//将前驱节点指向后面的节点
free(q);//释放内存
}
/*寻找任务链表中优先级最高的任务*/
Task_Node* LRtos_MaxPir(Task_Node* Plink) {
Task_Node* p,*q=NULL;
p = Plink->next;//指向第一个空闲任务
char maxpir=-1;
while (p) {
if (p->data.priority > maxpir) {
q = p;
maxpir = p->data.priority;
}
p = p->next;
}
return q;
}
//返回任务链表的长度.不算头结点,算空闲任务,不算挂起任务
int LRtos_ListLength(Task_Node* L) {
Task_Node* p;
int i = 0;
p = L->next;
while (p) {
if(p->data.prime_priority>=0)
i++;
p = p->next;
}
return i;
}
//恢复所有任务
void LRtos_TaskResumeALL(Task_Node* PNode) {
Task_Node* p= PNode;
p = p->next->next;//指向空闲任务后的第一个任务
while (p) {
// if(p->data.times==0|| (p->data.times_up < p->data.times))//如果是无限次运行的任务,或者是没有到达运行次数
LRtos_TaskResume_SYS(p);
p = p->next;
}
}
void LRtos_Open(Task_Node* Plink) {
Task_Node* Rtosp = NULL;
int len = 0;
while (1) {
len = LRtos_ListLength(Plink);
while (len--) {
//查找任务链表中优先级最高的任务
Rtosp = LRtos_MaxPir(Plink);
if (Rtosp == NULL)
Plink->next->data.task_hanger();//调用空闲任务
else {
//调用该任务
Rtosp->data.set_up(Rtosp);//先调用该任务的初始化函数,任务本体函数在这里面被调用
if(Rtosp->data.priority!=0)//如果不是空闲任务,则挂起
LRtos_TaskSuspend_SYS(Rtosp);//挂起
}
}
LRtos_TaskResumeALL(Plink);//一轮调用结束,恢复所有任务
}
}
然后基于目前的功能,一个测试如下:
#include "task.h"
Task_Node* taskLL;
void task1() {
printf("这里是任务一\n");
}
void task2() {
printf("这里是任务二\n");
}
int main(void) {
taskLL = PNode_Init();//创建了头结点;
printf("hello\n");
LRtos_init(taskLL);//LRtos初始化
LRtos_TaskCreate(taskLL, 1, task1, 2);
LRtos_TaskCreate(taskLL, 2, task2, 0);
LRtos_Open(taskLL);//开启任务调度
}
实验现象为
可以看到任务一运行两次之后被挂起,之后便没有运行,这个代码初步先这样,后面如果我在使用中有新的功能加入,这里也会更新