嵌入式实时操作系统的设计与开发New(八)
创建线程
用户在基于RTOS开发应用程序前,首先要创建线程。
用户创建一个线程时须指定用户希望采用的调度策略。
例如,用户想创建一个周期性执行的线程:
acoral_period_policy_data_t* data;
data = acoral_malloc(sizeof(acoral_period_policy_data_t));
data->prio=5;
data->prio_type=ACORAL_HARD_PRIO;
data->time=2000;acoral_crate_thread(test,512,NULL,"test",NULL,ACORAL_SCHED_POLICY_PERIOD,data);
int create_thread(void (*route)(void *args),unsigned int sttack_size,void *args,char *name,void *stack,unsigned int sched_policy,void *data){acoral_thread_t *thread;thread=alloc_thrad();if(NULL==thread){acoral_print("Alloc thread:%s fail\n",name);acoral_print("No Mem Space or Beyond the max thread\n");return -1;}thread->name = name;stack_size = stack_size&(~3); //将stack_size变量的值取为向下取整的4的倍数thread->stack_size = stack_size;if(stack!=NULL)thread->stack_buttom = (unsigned int *)stack;elsethread->stack_buttom=NULL;thread->policy = sched_policy;return acoral_policy_thread_init(sched_policy,threadd,route,args,data);
}
分配线程空间
创建线程需要做的第一项工作就是为该线程分配内存空间,线程是通过TCB描述的,为该线程分配内存空间就是为TCB分配内存空间,其返回值是刚分配的TCB的指针。
acoral_pool_ctr_t acoral_thread_pool_ctrl;acoral_thread_t *acoral_alloc_thread(){return (acoral_thread_t *)acoral_get_res(&acoral_thread_pool_ctrl);
}
/*资源池控制块*/
typedef struct{unsigned int type;//资源类型unsigned int size; //资源大小,如线程控制块大小,用sizeof(acoral_thread_t)赋值unsigned int num_per_pool;//每个资源池对象的个数unsigned int num; //已分配的资源池的个数unsigned int max_pools; //最多可以分配多少个资源池acoral_list_t *frree_pools; //空闲资源池链表acoral_list_t *pools,list[2];unsigned char *name;
}
资源池管理的资源内存是从第一级内存系统(伙伴系统)分配的,为了最大限度使用内存,减少内存碎片,对象的个数,最大值、可分配内存等都是通过计算后由用户指定的。
例如,伙伴算法设定基本内存块的大小为1KB,资源的大小为1KB,用户一个资源池包含20个资源,这样计算下来需要分配1x20=20KB的空间,而由于伙伴系统只能分配2i个基本内存块的大小,故会分配32KB,32KB可以包含32个资源对象,故每个资源池的对象的个数更改为32.
线程初始化
return acoral_policy_thread_init(sched_policy,thread,route,args,data);
int acoral_policy_thread_init(unsigned int policy,acoral_thread_t *thread,void (*route)(void *args),void *args,void *data){acoral_sched_policy_t *policy_ctrl;policy_ctrl = acoral_get_policy_ctrl(policy);if(policy_ctrl==NULL||polciy_ctrl->policy_thread_init==NULL){acoral_enter_critical();acoral_release_res((acoral_res_t *)thread);acoral_exit_critical();acoral_print("No thread policy support:%d\n",thread->policy);return -1;}return policy_ctrl->policy_thread_init(thread route args,data);
}
int period_policy_thread_init(acoral_thread_t *thread,void (*route)(void *args),void *args,void *data){unsigned int prio;acoral_period_policy_data_t *policy_data;period_private_data_t *private_data;if(thread->polciy==ACORAL_SCHED_POLICY_PERIOD){policy_data = (acoral_period_policy_data_t *)data;prio=policy_data->prio;if(policy_data->prio_type==ACORAL_NONHARD_PRIO){prio+=ACORAL_NONHARD_RT_PRIO_MAX;if(prio>=ACORAL_NONHARD_RT_PRIO_MIN)prio=ACORAL_NONHARD_RT_PRIO_MIN-1;}thread->prio = prio;private_data = (period_private_data_t *)acoral_malloc(sizeof(period_private_Data_t));if(private_data==NULL){acoral_print("No level2 mem space for private_data:%s\n",thread->name);acoral_enter_critical();acoral_release_res((acoral_res_t *)thread);acoral_exit_critical();return -1;}private_data->time=policy_data->time;private_data->route=route;private_data->args=args;thread->private_data=private_data;}if(acoral_thread_init(thread,route,period_thread_exit,args)!=0){acoral_print("No thread stack:%s\n",thread->name);acoral_enter_critical();acoral_release_res((acoral_res_t *)thread);acoral_exit_critical();return -1;}acoral_resume_thread(thread);acoral_enter_critical();period_thread_delay(thread,((period_private_data_t *)thread->private_data)->time);acoral_exit_critical();return thread->res.id;
}
堆栈初始化
acoral_list_t acoral_threads_queue;//全局所有线程队列unsigned int acoral_thread_init(acoral_thread_t *thread,void (route)(void *args),void (*exit)(void),void *args){unsigned int stack_size = thread->stack_size;if(thread->stack_buttom==NULL){ //判断堆栈指针是否为NULL,如果堆栈指针为NULL,说明需动态分配。if(stack_size<CFG_MIN_STACK_SIZE)stack_size=CFG_MIN_STACK_SIZE;thread->stack_buttom=(unsigned int *)acoral_malloc(stack_size);if(thread->stack_buttom==NULL)return ACORAL_ERR_THREAD_NO_STACK;thread->stack_size = stack_size;}thread->stack=(unsigned int *)((char *)thread->stack_buttom+stack_size-1);HAL_STACK_INIT(&thread->stack,route,exit,args);//模拟线程创建时的堆栈环境thread->data = NULL;thread->state = ACORAL_THREAD_STATE_SUSPEND;acoral_init_list(&thread->waiting);acoral_init_list(&thread->ready);acoral_init_list(&thread->timeout);acoral_init_list(&thread->global_list);acoral_enter_critical();acoral_list_add2_tail(&thread->global_list,&acoral_threads_queue);//将刚创建的线程挂到全局队列尾部acoral_exit_critical();return 0;
}
HAL_STACK_INIT()是与硬件相关的函数,不同处理器有不同寄存器,这些寄存器体现了当前线程的运行环境,如果当前线程被其它中断或线程所抢占,将发生上下文切换。
需要通过堆栈来保存被抢占线程的运行环境,那先保存哪个寄存器,再保存哪个寄存器?这就需要根据处理器的结构而定,HAL_STACK_INIT()就是用来规定寄存器保存顺序的。
typedef struct{unsigned int primask;unsigned int r4; ///<通用寄存器unsigned int r5; ///<通用寄存器unsigned int r6; ///<通用寄存器unsigned int r7; ///<通用寄存器unsigned int r8; ///<通用寄存器unsigned int r9; ///<通用寄存器unsigned int r10; ///<通用寄存器unsigned int r11; ///<通用寄存器unsigned int r0; ///<通用寄存器unsigned int r1; ///<通用寄存器unsigned int r2; ///<通用寄存器unsigned int r3; ///<通用寄存器unsigned int r12; ///<通用寄存器unsigned int lr;unsigned int pc;unsigned int cpsr;
}hal_ctx_t;
- primask:用于保存中断优先级屏蔽寄存器的值
- r0~r11:通用寄存器,用于保存临时变量、函数参数和返回值
- r12:通用寄存器,用于保存调用者的中间值
- lr:链接寄存器,保存跳转指令返回时的地址
- pc:程序计数器,保存当前正在执行的指令地址
- cpsr:程序状态寄存器,保存了当前CPU的状态,包括标志位和CPU模式等。
由于是用C语言来模拟线程创建时的堆栈环境,所以用宏转换定义hal_stack_init()来实现HAL_STACK_INIT()
HAL_STACK_INIT(&thread->stack,route,exit,args);
void hal_stack_init(acoral_u32 **stk,void (*route)(),void (*exti)(),void *args){hal_ctx_t *ctx = *stk;ctx--;ctx=(hal_ctx_t *)((unsigned int *)ctx+1);ctx->r0=(unsigned int)args;ctx->r1=0;ctx->r2=2;ctx->r3=3;ctx->r4=4;ctx->r5=5;ctx->r6=6;ctx->r7=7;ctx->r8=8;ctx->r9=9;ctx->r10=10;ctx->r11=11;ctx->r12=12;ctx->lr=(unsigned int)exit;ctx->pc=(unsigned int)route;ctx->primask=0;*stk=(unsigned int *)ctx; //将指针传给stk,而stk是用户创建堆栈指针变量地址
}
挂载线程到就绪队列
void resume_thrad(acoral_thread_t *thread){if(!(thread->state&ACORAL_THREAD_STATE_SUSPEND)) //如果当前状态不处于suspend状态,则不需要唤醒。return;acoral_enter_critical();acoral_rdyqueue_add(thread);acoral_exit_critical();acoral_sched();
}
void acoral_rdy_thread(acoral_thread_t *thread){if(!(ACORAL_THREAD_STATE_SUSPEND&thread->state))return;acoral_rdyqueue_add(thread);
}
//acoral就绪队列
typedef struct{unsigned int num;//就绪的线程数unsigned int bitmap[PRIO_BITMAP_SIZE];acoral_list_t queue[ACORAL_MAX_PRIO_NUM];
}acoral_rdy_queue_t;acoral_rdy_queue_t acoral_ready_queues;void acoral_rdyqueue_add(acoral_thread_t *thread){acoral_rdy_queue_t *rdy_queue;rdy_queue = &acoral_ready_queues;acoral_prio_queue_add(rdy_queue,thread->prio,&thread->ready);thread->state &= ~ACORAL_THREAD_STATE_SUSPEND;thread->state |= ACORAL_THREAD_STATE_READY;aoral_set_need_sched(true);
}
void acoral_prio_queue_add(acoral_rdy_queue_t *array,unsigned char prio,acoral_list_t *list){acoral_list_t *queue;acoral_list_t *head;array->num++;queue = array->queue + prio; //根据线程优先级找到线程所在的优先级链表head = queue;acoral_list_add_tail(list,head); //将该线程挂到优先级链表上acoral_set_bit(prio,array->bitmap);
}
调用acoral_sched()
一个普通线程创建的最后一步是调用内核调度函数acoral_sched()
真正意义上的多任务操作系统,都要通过一个调度程序(Scheduler)来实现调度功能,该调度程序以函数形式存在,用来实现操作系统的调度策略,可在内核的各个部分进行调用。
调用调度程序的具体位置又被称为是一个调度点,由于调度通常是由外部事件的中断来触发的,或者由周期性的时钟信号触发,因此调度点通常出于以下位置:
- 中断服务程序结束的位置。例如,当用户通过按键向系统提出新的请求,系统首先以中断服务程序ISR响应用户请求。然后在中断服务程序结束时创建新的任务,并将新任务挂载到就绪队列尾部。接下来,RTOS会进入一个调度点,调用调度程序,执行相应的调度策略。又如,当I/O中断发生时,如果I/O事是一个或多个任务正在等待的事件,则在I/O中断结束时刻,也将会进入一个调度点,调用调度程序,调度程序将根据调度策略确定是否继续执行当前处于运行状态的任务,或是让高优先级任务抢占低优先级任务。
- 运行任务因缺乏资源而被阻塞的时刻。例如,使用串口UART传输数据,如果UART此时正在被其他任务使用,这将导致当前任务从就绪状态变为等待状态,不能继续执行,而RTOS会进入一个调度点,调用调度程序。
- 任务周期开始或结束时。
- 高优先级任务就绪的时刻,如果采用基于优先级抢占式调度策略。
普通线程创建流程
- 为线程分配空间
- 然后根据创建线程的调度策略对线程TCB进行相关的初始化
- 然后对线程的堆栈进行初始化
- 将创建的线程挂到就绪队列上
- 供内核调度
相关文章:

嵌入式实时操作系统的设计与开发New(八)
创建线程 用户在基于RTOS开发应用程序前,首先要创建线程。 用户创建一个线程时须指定用户希望采用的调度策略。 例如,用户想创建一个周期性执行的线程: acoral_period_policy_data_t* data; data acoral_malloc(sizeof(acoral_period_poli…...

MySQL事务相关笔记
杂项 InnoDB最大特点:支持事务和行锁; MyISAM不支持事务 介绍 一个事务是由一条或者多条对数据库操作的SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完了,整个事务才会被提交给数据库。事务有如下特性…...

如何利用AI高效率快速调色
在设计行业中,时间是非常宝贵的资源,而设计师们常常需要应对繁忙的工作日程和紧迫的截止日期。为了提高工作效率和节省时间,越来越多的设计师开始利用人工智能(AI)技术中的高效调色功能。本文将介绍如何利用AI高效率快…...

数据结构--顺序表的基本操作--插入 and 删除
数据结构–顺序表的基本操作–插入 顺序表的插入操作 实现目标 ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。 typedef struct {int data[MaxSize];int len; }Sqlist;代码实现: #include <stdio.h> #include <stdlib.h> …...

BCSP-玄子Java开发之Java Web编程CH01_初识动态网页
BCSP-玄子Java开发之Java Web编程CH01_初识动态网页 1.1 B/S架构 B/S架构:浏览器/服务器 程序完全部署在服务器上使用浏览器访问服务器无需单独安装客户端软件 为什么要使用B/S架构 B/S与C/S比较B/S架构C/S架构软件安装浏览器需要专门的客户端应用升级维护客户…...

【软件教程】农林生环、水文、海洋、水环境、大气科学、人工智能、碳中和、碳排放、3S、R与统计等软件模型
本文涉及领域水文水资源、大气科学、农林生态、地信遥感、统计分析、编程语言等... 从软件基础到实践案例应用操作,手把手教学,提供永久回放观看和助学群长期辅助指导。适合课题组人员一站式学习,科研人员技术提升、企业单位工程项目、高校论…...

如何加入开源社
开源社成立于 2014 年,是由志愿贡献于开源事业的个人成员,依 “贡献、共识、共治” 原则所组成,始终维持厂商中立、公益、非营利的特点,是最早以 “开源治理、国际接轨、社区发展、项目孵化” 为使命的开源社区联合体。开源社积极…...

软件开发中的破窗效应
应该有很多人已经知道破窗效应【注1】这个社会学 (犯罪学)的词语,破窗效应最先由社会学家James Q. Wilson和George L. Kelling在一篇名为《Broken Windows》的文章中提出【注2】: “一个房子如果窗户破了,没有人去修补…...

机器视觉初步6-1:基于梯度的图像分割
把基于梯度的图像分割单独拿出来。 文章目录 一、图像梯度相关算子的原理1. Sobel算子2. Prewitt算子3. Roberts算子 二、python和halcon算子实现1.python实现2.halcon实现 基于梯度的图像分割方法利用像素之间的梯度信息来进行图像分割。 梯度 1是图像中像素灰度值变化最快的…...

从0开始,精通Go语言Rest微服务架构和开发
说在前面 现在拿到offer超级难,甚至连面试电话,一个都搞不到。 尼恩的技术社区中(50),很多小伙伴凭借 “左手云原生右手大数据”的绝活,拿到了offer,并且是非常优质的offer,据说年…...

Sui x KuCoin Labs夏季黑客松|本周Workshop预告
自Sui x KuCoin Labs夏季黑客松推出以来已有四周的时间,期间收获了众多开发者的积极报名和热情参与。随着黑客松报名即将进入尾声,同期举办的Workshop也迎来了本周的最后一波。本周的黑客松Workshop邀请到MoveEX和Mirror World的负责人作为嘉宾为大家带…...

从电源 LED 读取智能手机的秘密?
研究人员设计了一种新的攻击方法,通过记录读卡器或智能手机打开时的电源 LED,使用 iPhone 摄像头或商业监控系统恢复存储在智能卡和智能手机中的加密密钥。 众所周知,这是一种侧信道攻击。 通过密切监视功耗、声音、电磁辐射或执行操作所需…...

【Linux编辑器-vim使用】
目录 Linux编辑器-vim使用1.vim的基本概念2.vim的基本操作3.vim正常模式命令集4.vim末行模式命令集 Linux编辑器-vim使用 1.vim的基本概念 目前了解的vim有三种模式(其实有好多模式),分别是命令模式、插入模式和底行模式,各模式…...

安装Apache mysql php
目录 一.Apache网站服务 Apache——》静态页面处理——》将静态处理交给PHP Apache简介 安装Apache服务 编辑 安装软件思路 二.安装mysql数据库 1. 安装依赖包 2.创建程序用户管理 3.加压安装包 这边就安装完成了编辑 重点来了 报错了 没有空间 我最后的解决 方法…...

【人工智能】— 神经网络、前向传播、反向传播、梯度下降、局部最小值、多层前馈网络、缓解过拟合的策略
【人工智能】— 神经网络、前向传播、反向传播 前向传播反向传播梯度下降局部最小值多层前馈网络表示能力多层前馈网络局限缓解过拟合的策略 前向传播和反向传播都是神经网络训练中常用的重要算法。 前向传播是指将输入数据从输入层开始经过一系列的权重矩阵和激活函数的计算后…...

小文智能自定义变量详解
在小文交互场景设计时,有一个特殊功能,叫做自定义变量。有时,根据外呼对象的不同,需要对用户传达不同的内容,比如称呼、地址、公司名称等等。此时,就可以使用小文交互的自定义变量功能来实现对不同用户呼出…...
平面电磁波的反射与折射,极化滤波作用
目录 引言 反射定律和折射定律 反射系数和折射系数 平面电磁波在理想介质分界面上的全反射和全折射 全反射 全折射 极化滤波作用 平面电磁波在良导体上的反射与折射 引言 再复杂的电磁波我们都可以看作是很多平面电磁波的叠加 我们在前面介绍的时候,我们认…...

键盘当鼠标用
当鼠标坏掉又需要使用电脑时发现触控板也不能用这就很烦那么键盘当鼠标用教程来了 使用键盘当鼠标的步骤如下: 1. 按住“AltShiftNum Lock”快捷键,弹出鼠标键开启咨询框,点击“是”按钮。 小键盘的数字就是方向/和*就是左右键切换5是单击 …...

动态规划part9 | ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III
文章目录 198.打家劫舍思路思路代码官方题解代码 213.打家劫舍II思路思路代码官方代码困难 337.打家劫舍III思路思路代码官方题解代码困难 今日收获 198.打家劫舍 198.打家劫舍 思路 dp含义,偷前i个房,切第i个房偷 dp[i]max(dp[i-2],dp[i-3])nums[i] …...

【k8s系列】一分钟搭建MicroK8s Dashboard
本文基于上一篇文章的内容进行Dashboard搭建,如果没有看过上一篇的同学请先查阅上一篇文章 k8s系列】使用MicroK8s 5分钟搭建k8s集群含踩坑经验 使用MicroK8s搭建Dashboard很简单,只需要在Master节点按照以下几步操作 1.启用Dashboard插件 microk8s en…...

ArcEngine二次开发0——入门(下载 部署 组件学习)
折腾一下ArcGIS Engine二次开发。 目录 1、开发环境配置2、部署一个ArcGIS Engine应用程序3、ArcObject组件学习4、报错及解决4、其他 1、开发环境配置 参考:https://blog.csdn.net/H48662654/article/details/113384150 (使用ArcEngine前,…...

人工智能---D分离
D分离(D-Separation)是一种用来判断变量是否条件独立的图形化方法。相比于非图形化方法,D-Separation更加直观,且计算简单。对于一个DAG(有向无环图)E,D-Separation方法可以快速的判断出两个节点…...

java spring cloud 企业工程项目管理系统源码-全面的工程项目管理
工程项目管理系统是指从事工程项目管理的企业(以下简称工程项目管理企业)受业主委托,按照合同约定,代表业主对工程项目的组织实施进行全过程或若干阶段的管理和服务。 如今建筑行业竞争激烈,内卷严重,…...

2023最新软件测试面试题【1000道题含答案】
1、自动化代码中,用到了哪些设计模式? 单例设计模式 工厂模式PO设计模式数据驱动模式面向接口编程设计模式 2、什么是断言( Assert) ? 断言Assert用于在代码中验证实际结果是不是符合预期结果,如果测试用例执行失败会抛出异常并提供断言日志 3、什么是web自动化测…...

【目标跟踪】MOT数据集GroundTruth可视化
MOT数据集格式简介 MOT15数据集下载:https://pan.baidu.com/s/1foGrBXvsanW8BI4eybqfWg?pwd8888 以下为一行gt示例: 1,1,1367,393,73,225,1,-1,-1,-1 各列数据对应含义如下 <frame>,<id>,<bb_left>,<bb_top>,<bb_width&g…...

软件测试的概念与过程----学习软件测试前的思考
软件测试的概念与过程----学习软件测试前的思考 1、软件测试工作是做什么的?2、那我做软件测试拿到一个软件产品我应该从哪里测试,怎末开始工作?3、测试早做好还是晚一些做好?4、软件测试能将软件测试的一点问题都没有嘛ÿ…...

Streamlit基础教程
streamlit是什么 streamlit是一个开源的python库,它能够快速的帮助我们创建定制化的web应用,而且还非常便于和他人分享,特别是在机器学习和数据科学领域。整个过程不需要你了解任何前端的知识,包括html、css、javascript等&#x…...

内网穿透技术
文章目录 前言1. 安装JAVA2. MCSManager安装3.局域网访问MCSM4.创建我的世界服务器5.局域网联机测试6.安装cpolar内网穿透7. 配置公网访问地址8.远程联机测试9. 配置固定远程联机端口地址9.1 保留一个固定tcp地址9.2 配置固定公网TCP地址9.3 使用固定公网地址远程联机 转载自内…...

计算机网络笔记:内部网关协议RIP
文章目录 1.协议RIP的工作原理2.距离向量算法3.坏消息传播得慢 1.协议RIP的工作原理 RIP的地位:RIP是内部网关协议IGP中最先得到广泛使用的协议,其中文译名为路由信息协议。 RIP概述: RIP是一种分布式的基于距离向量的路由选择协议&#x…...

基于Java学生信息管理系统设计实现(源码+lw+部署文档+讲解等)
博主介绍: ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精…...