嵌入式实时操作系统的设计与开发(aCoral线程学习)

news2024/12/28 17:51:01

真正的RTOS,基本上没有做到进程,只是停留在多线程,因为多进程要解决很多问题,且需要硬件支持,这样就使得系统复杂了,从而就可能影响系统实时性。

线程之间是共享地址的,也就是说当前线程的地址相对于其它线程的地址是可见的,如果修改了地址的内容,其它线程是可以知道,并且能访问的。

int i = 1;
test()
{
	sleep(10);
	printf("%d",i);
}

int main()
{
	create_task(test,...);
	i++;
}

如果create_task对应的是创建线程的接口,则test输出2.
如果是创建进程的接口,则test输出1.
如果是多进程,main函数所在进程和test所在进程是不能相互访问彼此之间的变量的。

  1. 地址保护。每个进程都有自己的地址空间,如果当前进程跨界访问到了其它进程的区域,则会出错,就访问不了这个地址,这种地址保护需要硬件有存储器保护单元MPU(Memory Protectin Unit)的支持。
  2. 虚拟地址。各个进程仅管都是访问同一地址,但是由于虚拟地址隐射,他们对应的物理地址不一样,所以读取的值就会不一样。这种虚拟地址需要有内存管理单元MMU(Memory Managment Unit)的支持。

进程之间相互独立、隔离,一个进程的崩溃或错误操作不会影响其它进程。但无法直接访问全局变量,因为全局变量变成了进程范围内的全局变量了,这样进程之间的共享和通信就变得困难。

描述线程

线程就是一段代码的执行体。
线程保护了“执行代码+执行环境”,执行环境就是“堆栈+寄存器”。
线程控制块(TCB)是acoral_thread_t。

typedef struct{
	acoral_res_t res; //线程控制块是一种资源
	unsigned char state;
	...
}acoral_thread_t;

ACORAL_THREAD_EXIT为退出状态,意味着某个线程退出了,也就是说不会再参与调度,但此时该线程的资源,如线程控制块TCB、堆栈等资源还未释放,而RELEASE状态意味着可以释放这些资源。

  • CPU:指示线程在哪个CPU上运行,当前不支持线程迁移,也就是说,线程创建时在哪个CPU上,以后的整个执行过程也是在该CPU上。
  • acoral_list_t ready;
    acoral_list_t timeout;
    acoral_list_t waiting;
    acoral_list_t global_list;
  • stack:表示线程的堆栈。在当前线程被其它线程抢占,并在切换到其它线程的时候,当前线程的stack会赋值为CPU堆栈寄存器sp的值。每个线程都有自己的堆栈,用以存放自己的运行环境。
  • stack_buttom:这时栈底,一个线程的堆栈是有大小的,所以就有个栈底,当堆栈指针超过了栈底,是会出问题的。这时sp指向的内存地址已经不是本线程自己的内存空间,这样可能会破坏了其它线程的数据结构,严重时会导致系统崩溃。
  • stack_size:堆栈大小
  • delay:当用户需要延迟某个线程的执行时,用它来指定延迟的时间,单位是Ticks,当用户调用acoral_delay_self()时传入的时间参数转化为Tick再赋给delay成员。
  • private_deta:长久备用数据指针,用于线程策略私有数据指针。

res

typedef union{
   int id;
   int next_id;
}acoral_res_t;

由于线程控制块是一种资源,id表示线程的资源ID。
当某个资源空闲时,id的高16位表示该资源在资源池的编号,分配后表示该资源的ID。
next_id表示下一资源的ID,它是个空闲链表指针,指向下一个空闲的资源的编号,属于资源ID的一部分。
总之,res代表了线程的ID。
资源ID由资源类型Type和空闲内存池两部分组成。

采用了资源池的内存管理方式,资源池由结构acoral_pool_t定义。
若要创建某一新线程,将调用函数acoral_get_free_pool(),从空闲资源池中获取一空闲内存,并获取其ID号。将申请到的内存空间供该线程使用。

typedef struct {
   void *base_adr; //这有两个作用,在为空闲的时候,它指向下一个pool,否则为它管理的资源的基地址
   void *res_free; //指向下一空闲资源
   int id;
   unsigned int size;
   unsigned int num;
   unsigned int position;
   unsigned int free_num;
   acoral_pool_ctrl_t *ctrl;
   acoral_list_t ctrl_list;
   acoral_list_t free_list;
}acoral_pool_t;

空闲内存池ID由内存管理模块在初始化分配内存时,根据当前块数而定。

void acoral_res_sys_init()
{
	acoral_pool_t *pool;
	unsigned int i;
	pool = &acoral_pools[0];
	for(i=0; i<(ACORAL_MAX_POOLS-1); i++)
	{
		pool->base_adr = (void *)&acoral_pools[i+1]; //初始化时所有pool为空闲,故成员base_adr指向下一个pool
		pool->id = i;
		pool++;
	}
	pool->base_adr = (void *)0;
	acoral_free_res_pool = &acoral_pools[0];//空闲资源池指针
}
//创建资源内存池
unsigned int acoral_create_pool(acoral_pool_ctr_t *pool_ctrl)
{
	acoral_pool_t *pool;
	if(pool_ctr->num >= pool_ctrl->max_pools)
	{
		return ACORAL_RES_MAX_POOL;
	}
	pool = acoral_get_free_pool();
	if(pool == NULL)
		return ACORAL_RES_NO_POOL;
	pool->id = pool_ctrl->type << ACORAL_RES_TYPE_BIT | pool->id;
	pool->size = pool_ctrl->size;
	pool->num = pool_ctrl->num_per_pool;
	pool->base_adr = (void *)acoral_malloc(pool_size * pool->num);
	if(pool->base_adr == NULL)
		return ACORAL_RES_NO_MEM;
	pool->res_free = pool->base_adr;
	pool->free_num = pool->num;
	pool->ctrl = pool_ctrl;
	acoral_pool_res_init(pool);
	acoral_list_add2_tail(&pool->ctrl_list, pool_ctrl->pools);
	acoral_list_add2_tail(&pool->free_list, pool_ctrl->free_pools);
	pool_ctrl->num++;
	return 0;
}

Prio

#define CFG_MAX_THREAD (40)
#definne ACORAL_MAX_PRIO_NUM ((CFG_MAX_THREAD +1) & 0xff) //41,总共有40个线程,有0~40共41个优先级
#define ACORAL_MINI_PRIO CFG_MAX_THREAD //最低优先级40

typedef enum{
	ACORAL_INIT_PRIO, //init线程独有的0优先级
	ACORAL_MAX_POOL, //系统允许的最高优先级
	ACORAL_HARD_RT_PRIO_MAX, //硬实时任务最高优先级
	ACORAL_HARD_RT_PRIO_MIN = ACORAL_HARD_RT_PRIO_MAX+CFG_HARD_RT_PRIO_NUM,
	ACORAL_NOHARD_RT_PRIO_MAX, //非硬实时任务最高优先级

	ACORAL_DAEMON_PRIO = ACORAL_MINI_PRIO-2,
	ACORAL_NOHARD_RT_PRIO_MIN; //非硬实时任务最低优先级
	ACORAL_IDLE_PRIO;
}PrioEnum;

优先级与数字成反比,数字越大,优先级越低。
aCoral的初始优先级为0,最高优先级是1,最小优先级是总的优先级数减1。

#define CFG_MEM2 1 //任意大小内存分配系统是否启用
#define CFG_MEM2_SIZE (1024000) //任意大小内存分配系统的大小,是从伙伴系统管理的内存中拿出一部分
#define CFG_MIN_STACK_SIZE (512) //线程最小拥有的字节数

双向链表

acoral_list_t ready; //用于挂载全局就绪队列
acoral_list_t timeout; //超时阻塞
acoral_list_t waiting; //延时
acoral_list_t global_list; //全局线程列表
struct acoral_list{
	struct acoral_list *next,*prev;
};
typedef struct acoral_list acoral_list_t;

这4个acoral_list_t成员用来将线程结构挂到相应链表队列上。
在这里插入图片描述
以就绪队列ready为例,当用户调用了acoral_rdy_thread或acoral_resume_thread接口时,就会将线程挂到就绪队列acoral_ready_queue上,这就是将就绪队列ready成员挂到这个链表上。

挂到相应链表队列上的方式与Linux类似,这种方式的优点是:可以用相同的数据处理方式来描述所有双向链表,不用再单独为各个链表编写各种函数。

线程优先级

aCoral是一个支持多核的RTOS,因此,在开发初期就得考虑线程数量的问题。

aCoral的就绪队列采用的是优先级链表,每个优先级是一个链表,相同的优先级的线程都挂在该链表上。

对于RTOS而言,几乎都是采用了基于优先级的抢占调度策略。

typedef struct{
	unsigned int num; //就绪的线程数
	unsigned int bitmap[PRIO_BITMAP_SIZE];//优先级位图,每一位对应一个优先级,为1表示这个优先级有就绪线程
	acoral_list_t queue[ACORAL_MAX_PRIO_NUM]; //每一个优先级都有独立的队列
}acoral_rdy_queue_t;
  • num:定义了就绪任务的总数
  • bitmap[PRIO_BITMAP_SIZE]:用来标识某一优先级是否有就绪队列,这样才能确保以O(1)复杂度找出最高优先级的线程。
#define PRIO_BITMAP_SIZE ((ACORAL_MAX_PRIO_NUM+31)/32)

就绪队列中的优先级位图的大小,目前等于2,优先级数目除以32向上取整。

每个变量从右到左每一位依次代表一个优先级。

aCoral采用私有就绪队列,也就是每个CPU有一个就绪队列。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1100658.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

损失函数总结(一):损失函数介绍

损失函数总结&#xff08;一&#xff09;&#xff1a;损失函数介绍 1 引言2 损失函数是什么3 为什么要使用损失函数4 总结 1 引言 在网络模型进行训练时&#xff0c;激活函数、损失函数、优化器都会成为影响模型最终效果的关键因素。其中&#xff0c;激活函数和损失函数根据任…

vue3 v-md-editor markdown编辑器(VMdEditor)和预览组件(VMdPreview )的使用

vue3 v-md-editor markdown编辑器和预览组件的使用 概述安装支持vue3版本使用1.使用markdown编辑器 VMdEditor2.markdown文本格式前端渲染 VMdPreview 例子效果代码部分 完整代码 概述 v-md-editor 是基于 Vue 开发的 markdown 编辑器组件 轻量版编辑器 轻量版编辑器左侧编辑…

智慧党建小程序源码系统+在线答题考试二合一 带完整的搭建教程

大家好&#xff0c;今天来给大家分享一个智慧党建小程序源码系统。以下是部分核心代码图&#xff1a; 系统特色功能一览&#xff1a; 积分体系&#xff1a;党员可以通过完成各种党建活动&#xff0c;如学习党的理论知识、参加组织生活、开展志愿服务等获得积分&#xff0c;积分…

【JVM】synchronized与锁升级

文章目录 1. synchronized锁优化背景2. synchronized锁性能优化过程2.1 java5以前2.2 monitor锁2.3 java6开始 3. 无锁4. 偏向锁4.1 背景4.2 理论落地4.3 技术实现4.4 偏向锁的撤销4.5 题外话 5. 轻量级锁5.1 轻量级锁的加锁5.2 轻量级锁的释放5.3 锁升级 6. 重量级锁7. 锁升级…

本地安装telepresence,访问K8S集群 Mac(m1) 非管理員

kubeconfig 一&#xff0e;安装telepresence 1.安装 Telepresence Quickstart | Telepresence &#xff08;1&#xff09;brew install datawire/blackbird/telepresence 2.配置 目录kubectl 将使用默认的 kubeconfig 文件&#xff1a;$HOME/.kube/config 创建文件夹&…

集成电路CD40161-多功能计数器和分频器的重要性 | 百能云芯

在电子电路和数字系统设计中&#xff0c;CD40161是一款常用的集成电路&#xff08;IC&#xff09;元件。它是一个多功能的计数器和分频器&#xff0c;具有广泛的应用领域。云芯将带您深入解释CD40161的功能、特点、应用以及未来前景&#xff0c;帮助您更好地了解这一电子元件。…

小程序开发平台源码系统+全功能小程序商城功能 带前后端完整搭建教程

今天来给大家介绍一下小程序开发平台源码系统的全功能小程序商城功能。全功能小程序商城是一种基于微信平台开发的电子商务应用&#xff0c;它通过小程序商城为商家提供了一站式电子商务解决方案&#xff0c;帮助商家实现线上购物的便利。下面是部分核心代码图&#xff1a; 系统…

玩转代码| Vue 中 JSX 的特性,这一篇讲的明明白白

目录 什么时候使用JSX JSX在Vue2中的基本使用 配置 文本插值 条件与循环渲染 属性绑定 事件绑定 v-show与v-model 插槽 使用自定义组件 在method里返回JSX JSX是一种Javascript的语法扩展&#xff0c;即具备了Javascript的全部功能&#xff0c;同时又兼具html的语义…

八、单臂路由实验

拓扑图&#xff1a; 单臂路由的特点&#xff0c;基于VLAN实现在一个路由器同一个端口下&#xff0c;不同网段相互通讯 首先对各个PC机ip配置完毕 进入SW1&#xff0c;首先创建vlan 10 20 进入2 3口配置access分别允许10 20通过&#xff0c;进入1 4口配置trunk允许10和20通过 …

小程序开发平台源码系统——美容美发行业小程序功能 带完整搭建教程

今天来给大家介绍一下小程序开发平台其中的美容美发行业小程序开发的功能。在我们现在的日常生活中&#xff0c;美容美发行业都无处不在&#xff0c;而创建一个小程序可以帮助美容美发店更好地进行营销推广。通过在小程序中发布优惠活动、打折信息等&#xff0c;可以吸引更多的…

SAP ME21N\ME22N\ME23N采购订单增强:抬头、行项目取值处理

采购订单增强&#xff1a;ME_PROCESS_PO_CUST 抬头&#xff1a; HEADERDATA: ls_mepoheader TYPE mepoheader.ls_mepoheader im_header->get_data( ). 行项目&#xff1a; ITEMDATA: ls_mepoitem TYPE mepoitem,ls_customer TYPE mepo_badi_exampl,ls_tbsg TYPE tb…

yolov8训练自定义目标检测模型

本文使用Ultralytics的python API进行模型训练&#xff0c;适用于yolov8小白入门&#xff0c;大佬请忽略本文 笔者也是昨天开始学习的小白&#xff0c;如有错误希望多多指正 目录 准备数据集 python安装yolov8 配置yaml 从0开始训练 从预训练模型开始训练 准备数据集 …

Matlab论文插图绘制模板第120期—分组气泡云图

​在之前的文章中&#xff0c;分享了Matlab气泡云图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一下分组气泡云图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下载。有需要的朋友可以关注…

【Vue】vue在Windows平台IIS的部署

系列文章 【C#】IIS平台下&#xff0c;WebAPI发布及异常处理 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126539836 【Vue】vue2与WebApi跨域CORS问题 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/133808959 文章目…

新闻发稿多少钱一篇?轻松发布新闻一站式发稿服务平台

随着互联网的发展&#xff0c;新闻发布成为企业和个人宣传推广的重要手段之一。而在选择新闻发稿平台时&#xff0c;费用是一个关键因素。对于很多人而言&#xff0c;关心的问题是&#xff1a;新闻发稿多少钱一篇&#xff1f;是否有平价的选择&#xff1f;在这个方面&#xff0…

前端开发中的try...catch

首先try...catch 结构可以用来处理 Promise 中的异常。在 JavaScript 中&#xff0c;Promise 提供了一种处理异步操作的机制&#xff0c;并且可以通过 .catch() 方法捕获并处理异步操作中抛出的异常。 async function someAsyncFunction() {try {const result await someProm…

LPWAN产业何时才能真正爆发?

导读&#xff1a; 虽然LPWAN目前还有重重困难&#xff0c;但是我们有充分的理由相信LPWAN即将爆发的趋势不变&#xff0c;当然&#xff0c;因为LPWAN是一个技术流派繁多的市场&#xff0c;除了LoRa、NB-IOT、eMTC还有RPMA、ZETA等等众多的技术流派&#xff0c;对于应用企业而言…

01【Git的基本使用与底层命令】

下一篇&#xff1a;02【Git的分支与数据恢复】 目录&#xff1a;【Git系列教程-目录大纲】 文章目录 一、Git概述1.1 Git简介1.2 集中式与分布式1.2.1 集中式版本控制1.2.2 分布式版本控制 1.3 Git的使用流程1.3.1 本地仓库1.3.2 协同开发 1.4 Git的配置1.4.1 Git的配置等级1…

Java——List接口

1.Java单列集合类&#xff08;Collection&#xff09;概述 Java中的集合类就像一个容器&#xff0c;专门用来存储Java类的对象。 数组可以用来保存对个对象&#xff0c;但有时无法事先确定需要保存对象的个数&#xff0c;此时数组便不再使用&#xff0c;因为数组的长度不可变…

小黑怀柔证书下来,腿部酸痛也得到了缓解,跟跑团里的毛毛一起遛龙潭中湖公园,过两天要走闭幕式的leetode之旅的leetcode之旅:18. 四数之和

小黑代码(小黑独立做出来) class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:# 数组长度n len(nums)if n < 4:return []# 排序nums.sort()def three_sum(target_, start, end):if end - start < 2:return []# 结果数组res []fo…