当前位置: 首页 > news >正文

嵌入式实时操作系统的设计与开发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)来实现调度功能,该调度程序以函数形式存在,用来实现操作系统的调度策略,可在内核的各个部分进行调用。
调用调度程序的具体位置又被称为是一个调度点,由于调度通常是由外部事件的中断来触发的,或者由周期性的时钟信号触发,因此调度点通常出于以下位置:

  1. 中断服务程序结束的位置。例如,当用户通过按键向系统提出新的请求,系统首先以中断服务程序ISR响应用户请求。然后在中断服务程序结束时创建新的任务,并将新任务挂载到就绪队列尾部。接下来,RTOS会进入一个调度点,调用调度程序,执行相应的调度策略。又如,当I/O中断发生时,如果I/O事是一个或多个任务正在等待的事件,则在I/O中断结束时刻,也将会进入一个调度点,调用调度程序,调度程序将根据调度策略确定是否继续执行当前处于运行状态的任务,或是让高优先级任务抢占低优先级任务。
  2. 运行任务因缺乏资源而被阻塞的时刻。例如,使用串口UART传输数据,如果UART此时正在被其他任务使用,这将导致当前任务从就绪状态变为等待状态,不能继续执行,而RTOS会进入一个调度点,调用调度程序。
  3. 任务周期开始或结束时。
  4. 高优先级任务就绪的时刻,如果采用基于优先级抢占式调度策略。

普通线程创建流程

  1. 为线程分配空间
  2. 然后根据创建线程的调度策略对线程TCB进行相关的初始化
  3. 然后对线程的堆栈进行初始化
  4. 将创建的线程挂到就绪队列上
  5. 供内核调度

相关文章:

嵌入式实时操作系统的设计与开发New(八)

创建线程 用户在基于RTOS开发应用程序前&#xff0c;首先要创建线程。 用户创建一个线程时须指定用户希望采用的调度策略。 例如&#xff0c;用户想创建一个周期性执行的线程&#xff1a; acoral_period_policy_data_t* data; data acoral_malloc(sizeof(acoral_period_poli…...

MySQL事务相关笔记

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

如何利用AI高效率快速调色

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

数据结构--顺序表的基本操作--插入 and 删除

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

BCSP-玄子Java开发之Java Web编程CH01_初识动态网页

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

【软件教程】农林生环、水文、海洋、水环境、大气科学、人工智能、碳中和、碳排放、3S、R与统计等软件模型

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

如何加入开源社

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

软件开发中的破窗效应

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

机器视觉初步6-1:基于梯度的图像分割

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

从0开始,精通Go语言Rest微服务架构和开发

说在前面 现在拿到offer超级难&#xff0c;甚至连面试电话&#xff0c;一个都搞不到。 尼恩的技术社区中&#xff08;50&#xff09;&#xff0c;很多小伙伴凭借 “左手云原生右手大数据”的绝活&#xff0c;拿到了offer&#xff0c;并且是非常优质的offer&#xff0c;据说年…...

Sui x KuCoin Labs夏季黑客松|本周Workshop预告

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

从电源 LED 读取智能手机的秘密?

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

【Linux编辑器-vim使用】

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

安装Apache mysql php

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

【人工智能】— 神经网络、前向传播、反向传播、梯度下降、局部最小值、多层前馈网络、缓解过拟合的策略

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

小文智能自定义变量详解

在小文交互场景设计时&#xff0c;有一个特殊功能&#xff0c;叫做自定义变量。有时&#xff0c;根据外呼对象的不同&#xff0c;需要对用户传达不同的内容&#xff0c;比如称呼、地址、公司名称等等。此时&#xff0c;就可以使用小文交互的自定义变量功能来实现对不同用户呼出…...

平面电磁波的反射与折射,极化滤波作用

目录 引言 反射定律和折射定律 反射系数和折射系数 平面电磁波在理想介质分界面上的全反射和全折射 全反射 全折射 极化滤波作用 平面电磁波在良导体上的反射与折射 引言 再复杂的电磁波我们都可以看作是很多平面电磁波的叠加 我们在前面介绍的时候&#xff0c;我们认…...

键盘当鼠标用

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

动态规划part9 | ● 198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

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

【k8s系列】一分钟搭建MicroK8s Dashboard

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

告别道路预测老套路:用ParkPredict+模型思路,解决停车场里的‘鬼探头’难题

破解泊车场景预测困局&#xff1a;ParkPredict模型的技术革新与实践停车场里的每一次转向、倒车和避让&#xff0c;都是对自动驾驶系统预测能力的极限挑战。与开放道路的规则明确不同&#xff0c;这里没有清晰的车道线指引&#xff0c;没有统一的行驶方向&#xff0c;只有随时可…...

[智能体-69]:重新认知MCP:协议不生产智能,只是AI全域交互的标准化基石

MCP只是提供了大模型、编排调度、外部工具能够进行结构化交流的标准&#xff0c;而整个系统的智能主要依赖编排调度&#xff0c;与外部软件系统的交互取决于外部工具&#xff0c;包括外部语音交互、视觉交互、数字化交互。当下MCP&#xff08;Model Context Protocol&#xff0…...

终极艾尔登法环帧率解锁指南:轻松突破60FPS限制

终极艾尔登法环帧率解锁指南&#xff1a;轻松突破60FPS限制 【免费下载链接】EldenRingFpsUnlockAndMore A small utility to remove frame rate limit, change FOV, add widescreen support and more for Elden Ring 项目地址: https://gitcode.com/gh_mirrors/el/EldenRing…...

《我看见的世界:李飞飞自传》第1-6章阅读笔记:从移民少女到AI教母的“看见“之旅

前言 当我们谈论人工智能时&#xff0c;我们谈论的是算法、数据、算力&#xff0c;是那些冰冷的代码和复杂的模型。但在《我看见的世界&#xff1a;李飞飞自传》中&#xff0c;李飞飞用她独特的视角告诉我们&#xff1a;AI的本质&#xff0c;是人类对"看见"世界的渴望…...

2026论文降AI怎么挑?亲测好用工具附免费降AI指南

“您的论文AIGC率为42%&#xff0c;超出学校30%的合格线&#xff0c;请修改后重新提交。”赶毕业论文的同学这段时间估计没少收到这样的提醒。2026年知网、万方、维普等主流平台的AI检测算法持续迭代&#xff0c;把AI生成内容改到符合学校要求&#xff0c;已经成了毕业生的刚需…...

碧蓝航线自动化脚本终极指南:3小时学会全自动游戏管理

碧蓝航线自动化脚本终极指南&#xff1a;3小时学会全自动游戏管理 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 还在为碧蓝…...

Arcmap实操:如何用‘渔网’给你的地图做一次‘CT扫描’——以韶关市路网密度可视化为例

Arcmap实操&#xff1a;如何用‘渔网’给你的地图做一次‘CT扫描’——以韶关市路网密度可视化为例 想象一下&#xff0c;医生通过CT扫描将人体内部结构分层呈现&#xff0c;而GIS中的"渔网"工具同样能对城市路网进行"切片式"分析。这种空间离散化技术&…...

NanaZip:现代Windows文件压缩问题的终极解决方案

NanaZip&#xff1a;现代Windows文件压缩问题的终极解决方案 【免费下载链接】NanaZip The 7-Zip derivative intended for the modern Windows experience 项目地址: https://gitcode.com/gh_mirrors/na/NanaZip 还在为Windows文件压缩工具界面老旧、功能单一而烦恼吗&…...

Unlock-Music:浏览器中一键解锁加密音乐文件的完整指南

Unlock-Music&#xff1a;浏览器中一键解锁加密音乐文件的完整指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库&#xff1a; 1. https://github.com/unlock-music/unlock-music &#xff1b;2. https://git.unlock-music.dev/um/web 项目地址: http…...

DeepSeek-R1代码补全实测报告:37个真实项目、8类编程语言、48小时压测后,我删掉了Copilot

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek-R1代码补全实测报告总览 DeepSeek-R1 是深度求索&#xff08;DeepSeek&#xff09;推出的开源大语言模型&#xff0c;专为代码理解与生成任务优化。本章聚焦其在主流 IDE 环境中代码补全能力的…...