嵌入式实时操作系统的设计与开发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…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

Python 实现 Web 静态服务器(HTTP 协议)
目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1)下载安装包2)配置环境变量3)安装镜像4)node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1)使用 http-server2)详解 …...