这篇文章主要介绍“怎么用C语言实现任务调度”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么用C语言实现任务调度”文章能帮助大家解决问题。
整体上的结构属于线性结构,结合链表和定时器来实现,我使用的是sysTick
这个滴答时钟,1ms
的频率,功能比较简单,容易理解。
分片的模式,主要体现在函数分片和时间分片在我之前就有使用在函数中,主要的思路是,把函数功能切片,分为几个小部分,每次执行时按次序执行小部分,对于没有时序要求的函数来说,可以把一个占用CPU
大的功能分摊开来实现,从而避免有些地方耗时长的问题。对于时间分片,其实就是定时器的一种应用,实际上,函数分片在执行的时候已经是一种时间分片了,不过现在加上人为的控制在里面了。
下面是函数分片的一般结构:
void func(char *fos,...){ static char step=0;//顺序控制变量,自由度比较高,可乱序,可循环,可延迟执行 switch(step){ case 0:{ //... step++; break; } case 1:{ //... step++; break; } //... default:{ //step++;//可以借助default实现延时的效果,即跳过几次空白step break; } } return; }
其中添加的参数变量*fos
是必要的,因为就是通过传入每个任务的这个标志位来判断是否运行结束,而其他的参数,就得基于具体任务做不一样的处理了。
运行框图
可以看到这个框图是一个头尾相连的闭环结构,从头节点依次运行到尾节点后再从头循环往复执行下去。
轮询函数
void loop_task(void){ static Task_Obj *tasknode; tasknode=task_curnode->next;//repoint the curnode to the next if(tasknode==NULL){//tasknode is null,only the headnode have the attr return;//express the task space is none } else if(tasknode->task_type==TYPE_HEAD){//tasknode is headnode task_curnode=tasknode; return; } else{ if(tasknode->run_type == RUN_WAIT){ //等待型任务,通过ready标志来确定是否执行,否则就跳过 if(!tasknode->ready){ if(task_curnode->next !=NULL){ task_curnode=task_curnode->next; return; } } } if(tasknode->task_status==STATUS_INIT){ tasknode->tickstart=HAL_GetTick();//获取tick tasknode->task_status=STATUS_RUN; } else if(tasknode->task_status==STATUS_RUN){ if((HAL_GetTick() - tasknode->tickstart) > (uint32_t)tasknode->task_tick){ tasknode->task_name(&(tasknode->task_fos));//run the step task,transfer the fos tasknode->tickstart+=(uint32_t)tasknode->task_tick;//update the tickstart } } } if(tasknode->task_fos==FOS_FLAG){ tasknode->ready=0; if(tasknode->waittask!=NULL){ //置位该任务绑定的等待的任务准备运行标志位,标识可以准备运行了 tasknode->waittask->ready=1; } //运行结束就删掉该任务 delete_task(tasknode); } else if(tasknode->task_fos==FOC_FLAG){ //循环运行该任务 tasknode->task_status=STATUS_INIT;//continue running from start tasknode->task_fos=0;//RESET fos } if(task_curnode->next !=NULL){ if(task_curnode->next->run_type==RUN_FORCE) return;//force-type's task else task_curnode=task_curnode->next; } }
其中有几个运行态和标志位
#define FOS_FLAG 99//运行结束标志 #define FOC_FLAG 100//运行结束后再次执行,相当于循环运行 #define TYPE_NOMAL 0//标识一般任务类型 #define TYPE_HEAD 1//标识头任务类型 #define TYPE_END 2//标识尾任务类型 #define RUN_NORMAL 0//一般轮询模式 #define RUN_FORCE 1//强制运行该任务,运行结束才继续下一个任务 #define RUN_WAIT 2//等待指定的任务结束,才可以被运行 #define STATUS_INIT 0//任务的准备阶段,用于获取起始时间 #define STATUS_RUN 1//任务运行阶段 #define STATUS_UNVAILED 2//无效状态
运行时对时间间隔tick
的把握还有点问题,这个等待后面有机会优化下。
任务链表结构
typedef struct TASK_CLASS{ void (*task_name)(char *taskfos,...);//任务函数 int task_tick;//任务的时间分片间隔 uint32_t tickstart;//起始时间点,每次执行完须加上一个tick char task_fos;//运行结束标志 char task_type;//任务类型变量 char task_status;//任务状态 char run_type;//运行状态 char ready;//准备运行标志位 struct TASK_CLASS *next;//下一任务 struct TASK_CLASS *waittask;//等待执行的任务 } Task_Obj;
添加任务
add_task
void add_task(void (*taskname)(char *,...),int tasktick,int runtype){//可变参,这里未做处理 Task_Obj *tasknode,*tmpnode; char i; tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=taskname; tasknode->task_tick=tasktick; tasknode->task_fos=0; tasknode->task_status=STATUS_INIT;//initial status tasknode->task_type=TYPE_END; //set the new node to endnode tasknode->run_type=runtype; tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode=&task_headnode; if(task_num==0){ tmpnode->next=tasknode; task_num++; return; } for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode } tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node tmpnode->next=tasknode; task_num++; }
add_wait_task
void add_wait_task(void (*taskname)(char *),void (*waitname)(char *),int tasktick){ Task_Obj *tmpnode,*tasknode; char i,pos; tmpnode=&task_headnode; for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode if(tmpnode->task_name==taskname){ pos=i;//获取要等待任务的位置 break; } } tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=waitname; tasknode->task_tick=tasktick; tasknode->task_fos=0; tasknode->task_status=STATUS_INIT;//initial status tasknode->task_type=TYPE_END; //set the new node to endnode tasknode->run_type=RUN_WAIT;//任务为等待运行 tasknode->ready=0; tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode->waittask=tasknode;//获取新建的等待执行的任务地址,在运行结束后把等待执行的任务的准备运行标志位置1 tmpnode=&task_headnode; if(task_num==0){ tmpnode->next=tasknode; task_num++; return; } for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode } tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node tmpnode->next=tasknode; task_num++; }
删除任务
delete_task(局限性大,只针对当前运行的任务而言)
void delete_task(Task_Obj *taskobj){ if(task_curnode->task_type==TYPE_HEAD && task_num < 2){//if curnode is headnode,and tasknum=1 task_curnode->next=NULL; } else{ task_curnode->next=taskobj->next;//repoint the curnode next } free(taskobj);//free the space of where the taskobj pointed task_num--; }
delete_task_withname(删除指定任务名的任务)
void delete_task_withname(void (*taskname)(char *)){ Task_Obj *tmpnode,*tmpnode2; char i,pos; tmpnode=&task_headnode; for(i=0;i<task_num;i++){ tmpnode=tmpnode->next;//reach the endnode if(tmpnode->task_name==taskname){ pos=i; break; } } if(i==task_num) return; tmpnode=&task_headnode; for(i=0;i<pos+1;i++){ tmpnode2=tmpnode; tmpnode=tmpnode->next; } if(tmpnode->next==NULL){//if tmpnode is endnode tmpnode2->next=&task_headnode; } else{ tmpnode2->next=tmpnode->next;//repoint the curnode next } task_num--; free(tmpnode); }
初始化任务空间
void non_task(char *taskfos){ return; } void init_taskspace(void){ task_headnode.task_name=non_task; task_headnode.task_type=TYPE_HEAD; task_headnode.task_status=STATUS_UNVAILED; task_headnode.next=NULL; task_curnode=&task_headnode;//头节点是没有任务需要执行的 task_num=0; }
调用实例
add_task(task1,500,RUN_NORMAL);//500ms执行一次task1任务 add_wait_task(task1,task2,500);//task2等待task1结束才会执行,运行的时间间隔为500ms delete_task_withname(task1);//删除task1任务 while(1){ //... loop_task();//任务轮询 }
关于“怎么用C语言实现任务调度”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。