
其次同时使用面向对象的设计思维,将任务设计为一个抽象的对象,任务对象将任务的信息封装起来,这样就提高了软件的扩展性和复用性。虽然C语言不是面向对象编程语言,但是通过一些设计技巧可以实现面向对象设计。最后构建一个任务链表用于加入和删除任务。链表数据结构可以在保留原有物理顺序的情况下,高效地插入和删除。
软件环境是使用的KEIL V5.2 开发工具。
任务栈指针为第一个元素,这样栈指针就和任务对象为同一个地址(结构体的第一个元素就是结构体的首地址),这样就可以极大的简化任务切换过程中对栈指针的操作。任务栈指针指向用户为任务定义的静态数据块,通常情况下任务栈是一个全局静态数组,数组的大小就是任务栈的大小。
任务链表的作用是将多个任务串联起来,方便依次检索和操作。
链表采用的是数据中包含链表的数据结构,采用这种方式的优点是:当用户数据结构改变时,整个链表结构可以保持不变,不同的用户数据可以通用这一个的链表结构。示意图如下:
数据中包含链表的数据结构,在操作链表后无法得到整个数据对象的地址。由下图可知图可知我们通过next指针可以得到下一个list元素的地址,但是我们无法获取整个数据对象的地址。
在链表结构中增加一个void * owner指针,void *
类型指针可以指向任意类型的对象,用这个指针指向整个数据对象的地址,这样就可以定位到整个数据对象的地址。
struct list_node_def
{
struct list_node_def * next; /* 指向下一个列表节点 */
struct list_node_def * previous; /* 指向上一个列表节点 */
void *owner; /* 指向链表节点数据结构 */
};typedef struct list_def
{
list_node_t *index; /* 索引指针 */
list_node_t head; /* 列表头 */
} list_t;
在创建任务之前,需要定义任务栈空间和用户任务函数:/*********************************************************************************************************
* @名称 : enuo
* @作者 : 李巍
**********************************************************************************************************/
#define STACK_NUM (64)
/* 任务0-任务2栈空间 */
uint32_t task0_stack[STACK_NUM];
uint32_t task1_stack[STACK_NUM];
uint32_t task2_stack[STACK_NUM];
/* 任务0-任务2对象*/
task_tcb_t my_task0;
task_tcb_t my_task1;
task_tcb_t my_task2;
void task0(void)
{
static uint16_t clk = 0;
while(1)
{
if( ( ( clk++ )%9999 ) == 0 )
{
task_debug_num0++; /* 测试跟踪 */
test_function();
}
}
}void task_create(task_tcb_t *task , task_function_t function ,uint32_t *stack_space ,uint32_t stack_number)
{
list_node_t * node_tail = &task_list.head;
/* 寻求列表尾端 */
while( node_tail->next != NULL )
node_tail = node_tail->next;
/* 任务列表加入下一个任务 */
node_tail->next = &task->task_list;
/* 列表所有者指针指向任务 */
task->task_list.owner = task;
/* 当前任务下个列表指针设置为空 */
task->task_list.next = NULL;
/* 初始化任务栈 */
task_stack_init( (uint32_t *)task, function , stack_space , stack_number );
}void task_stack_init(uint32_t *stack_pointer ,
task_function_t task ,
uint32_t *stack_space ,
uint32_t stack_number)
{
/* 将任务psp栈指针指向任务栈底部*/
*stack_pointer = ( (uint32_t)stack_space + ( (stack_number - 16)<<2 ) );
/* 初始化任务栈中的程序寄存器 */
*( (uint32_t *)( (uint32_t )( *stack_pointer) + (14<<2) ) ) = ( uint32_t )task;
/* 初始化任务栈中的XPSR*/
*( (uint32_t *)( (uint32_t )( *stack_pointer) + (15<<2) ) ) = 0x01000000;
}
enuo_schedule函数代码如下:/*********************************************************************************************************
* @名称 : enuo
* @作者 : 李巍
**********************************************************************************************************/
__asm void start_schedule(void)
{
/* 设置CONTROL寄存器 配置PSP栈指针模式 */
MOV R0 ,#0X02
MSR CONTROL,R0
/*读取current_task 地址 */
LDR R3, =__cpp(¤t_task)
/* 读取curr_task中的PSP指针数值 */
LDR R1,[R3]
LDR R0,[R1]
/* 出栈R4-R11八个寄存器 */
LDMIA R0!,{R4-R11}
/* 设置PSP指针 */
MSR PSP,R0
/* POP 寄存器 POP PC实现跳转 */
POP { R0-R3 , R12 ,R11 ,PC }
/* 对齐 */
ALIGN 4
}/*********************************************************************************************************
* @名称 : enuo
* @作者 : 李巍
**********************************************************************************************************/
void SysTick_Handler(void)
{
static list_node_t * node_tail = &task_list.head;
/* 轮流切换任务 */
if(node_tail->next != NULL )
{
/* 当下一个列表项不为NULL时 next_task为下一个列表项指向的任务*/
next_task = node_tail->next->owner;
/* 更新任务指针 */
node_tail = node_tail->next;
}
else
{
/* 当下一个列表项为NULL时 ,node_tail指向任务列表的表头*/
node_tail = &task_list.head;
/* next_task为表头指向的下一个的任务*/
next_task = node_tail->next->owner;
node_tail = node_tail->next;
}
/* PendSV系统中断置位 */
SCB->ICSR |=SCB_ICSR_PENDSVSET_Msk;
return;
}/*********************************************************************************************************
* @名称 : enuo
* @作者 : 李巍
**********************************************************************************************************/
__asm void PendSV_Handler(void)
{
/* 读取当前进程栈指针数值 */
MRS R0,PSP
//isb
/* 保存R4-R11八个寄存器的值到当前任务栈中 同时将回写的地址写入R0 */
STMDB R0!,{R4-R11}
/* 读取current_task 栈指针地址 */
LDR R3, =__cpp(¤t_task)
LDR R3, [R3]
/* 将当前进程PSP指针值 写入 相应的 current_task */
STR R0,[R3]
/* 获取next_task 栈指针地址 */
LDR R4,=__cpp(&next_task)
LDR R4,[R4]
/* 读取next_task中的stack_point指针 */
LDR R0,[R4]
/* 更新current_task */
LDR R3, =__cpp(¤t_task)
STR R4,[R3]
/* 出栈 R4-R11八个寄存器 */
LDMIA R0!,{R4-R11}
/* 设置PSP指针 */
MSR PSP,R0
/* 中断返回 */
BX LR
/* 对齐 */
ALIGN 4
}
运行结果反应创建的3个任务都得到了调度,说明enuo系统正常工作。enuo系统目前包括3个文件:
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
我正在开发一个Rails应用程序,我需要在其中找到给定特定偏移量或时区的夏令时开始和结束日期。我基本上在我的数据库中保存了从用户浏览器接收到的时区偏移量(“+3”,“-5”),我想在它出现时修改它由于夏令时的变化。我知道Time实例变量有dst?和isdst方法,如果存储在它们中的日期在夏令时与否。>Time.new.isdst=>true但是使用它来查找夏令时的开始和结束日期会占用太多资源,而且我还必须为我拥有的每个时区偏移量执行此操作。我想知道更好的方法。 最佳答案 好的,基于你所说的和@dhouty'sanswer:您希望能够
关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和
我有一台生产机器和一台开发机器,都运行ubuntu8.10并且都运行最新的phusionpassenger。当我在osx上的本地开发机器上使用ruby1.9.1时,我想知道外面的人是否已经在使用带有ruby1.9.1甚至1.9.2的phusionpassenger?如果是这样,请告诉我们您的设置!此外,有没有办法在apache上使用phusionpassenger同时运行ruby1.8.7(ree)和1.9.1?感谢您的指点,我在任何地方都找不到任何提示... 最佳答案 是的,从某些2.2.x版本开始就正式支持它,我不记
date_select方法只能设置:start_year,但我想设置开始日期(例如3个月前的日期)(但没有这样的选项)。那么,我可以将开始日期设置为date_select方法吗?或者,要制作这样的选择框,我应该使用select_tag和options_for_select吗?或者,有什么解决办法吗?谢谢, 最佳答案 有可能……例如:start_year–设置年份选择的开始年份。默认为Time.now.year-5参见thisresource. 关于ruby-Rails3-我可以将开始日期
在我的mac上安装几个东西时遇到这个问题,我认为这个问题来自将我的豹子升级到雪豹。我认为这个问题也与macports有关。/usr/local/lib/libz.1.dylib,filewasbuiltfori386whichisnotthearchitecturebeinglinked(x86_64)有什么想法吗?更新更具体地说,这发生在安装nokogirigem时日志看起来像:xslt_stylesheet.c:127:warning:passingargument1of‘Nokogiri_wrap_xml_document’withdifferentwidthduetoproto
我想从特定索引开始遍历数组。我该怎么做?myj.eachdo|temp|...end 最佳答案 执行以下操作:your_array[your_index..-1].eachdo|temp|###end 关于ruby-从特定索引开始迭代数组,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/44151758/
参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍 介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。 内容有: ①:Hub模型的方法介绍 ②:服务器端代码介绍 ③:前端vue3安装并调用后端方法 ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke() 去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on