多任务编程----Kithara RTS工程源码解析

本文以windows实时拓展Kithara RTS安装目录下的smp文件夹内的TaskSimple项目为例,解读Kithara
RTS的实时多任务编程方法。

该项目只有一个工程TaskSimple,工程内的TaskSimple.cpp文件实现了主要功能,使用了Kithara
RTS的kernel模块和Task模块

TaskSimple.cpp文件主要由5部分组成,共享内存结构体,三个任务回调函数,一个主函数runSample

共享内存结构体:


//------ CallBackData ------
struct CallBackData {
Handle hTaskA_;
Handle hTaskB_;
Handle hTaskC_;
Handle hPipe_;
};

CallBackData内部有3个任务句柄和一个用于数据交互的hPipe_对象。

///////////////////////////////////////////////////////////////////////////

runSample函数的主要功能代码:


ksError = KS_openDriver(//打开驱动,这是使用Kithara RTS的第一步
pCustomerNumber); // Customer number
if (ksError) {
outputErr(ksError, "KS_openDriver", "Maybe incorrect customer number?");
return;
}

//------------------------------------------------------------------------------------------------------------
// Allocation of Sharedmem
//------------------------------------------------------------------------------------------------------------

CallBackData* pAppPtr;
CallBackData* pSysPtr;
ksError = KS_createSharedMem(//创建共享内存
(void**)&pAppPtr, // App Pointer,应用层指针,只能在应用层中使用
(void**)&pSysPtr, // Sys Pointer,内核层指针,只能在内核层中使用
NULL, // Name,名称
sizeof(CallBackData), // Size,共享内存空间大小
0); // Flags,标志位,这里设置为0即可
//注意如果内核层使用了pAppPtr或者应用层使用了pSysPtr会造成系统崩溃
if (ksError != KS_OK) {
outputErr(ksError, "KS_createSharedMem", "Failed to allocate shared memory");
KS_closeDriver();
return;
}

//------------------------------------------------------------------------------------------------------------
// For data transfer we use a pipe.
//------------------------------------------------------------------------------------------------------------

ksError = KS_createPipe(//创建数据管道,用于任务之间的数据交互
&pAppPtr->hPipe_, // Pipe Handle ,句柄,在共享内存中
"MyTaskSimplePipe", // Name,名称
sizeof(char), // Item size, here size of pointer,单位大小
9, // Item count,管道长度
NULL, // Object to signal,触发对象,没有使用设置为null(空)
0); // Flags,标志位设置为0
if (ksError != KS_OK) {
outputErr(ksError, "KS_createPipe", "Unable to create pipe!");
KS_closeDriver();
return;
}

//------------------------------------------------------------------------------------------------------------
// Now we create the callbacks. The callback contains the KSF_DIRECT_EXEC: - execution on kernel level
//------------------------------------------------------------------------------------------------------------
//下面将3个函数体映射为3个回调函数,
Handle hCallbackA;
ksError = KS_createCallBack(//创建回调函数
&hCallbackA, // Address of callback handle,回调函数句柄
_callBackA, // Callback function,回调函数本体
pSysPtr, // Reference parameter to the callback,回调函数的参数
KSF_DIRECT_EXEC, // Flags,直接执行
0); // Priority (only on user level)
if (ksError != KS_OK) {
outputErr(ksError, "KS_createCallBack", "Failed to create callback");
KS_closeDriver();
return;
}
//参数pSysPtr对应回调函数的pArgs,由于回调函数运行在内核层因此其实用的参数也必须位于内核层
//pSysPtr是内核层参数,pAppPtr是用户层参数

Handle hCallbackB;
ksError = KS_createCallBack(
&hCallbackB, // Address of callback handle
_callBackB, // Callback function
pSysPtr, // Reference parameter to the callback
KSF_DIRECT_EXEC, // Flags
0); // Priority (only on user level)
if (ksError != KS_OK) {
outputErr(ksError, "KS_createCallBack", "Failed to create callback");
KS_closeDriver();
return;
}

Handle hCallbackC;
ksError = KS_createCallBack(
&hCallbackC, // Address of callback handle
_callBackC, // Callback function
pSysPtr, // Reference parameter to the callback
KSF_DIRECT_EXEC, // Flags
0); // Priority (only on user level)
if (ksError != KS_OK) {
outputErr(ksError, "KS_createCallBack", "Failed to create callback");
KS_closeDriver();
return;
}

//------------------------------------------------------------------------------------------------------------
// Create the tasks
// Task B and Task C are created with KSF_DONT_START, so they are suspended.
// Task A executes immediately after creation.
//------------------------------------------------------------------------------------------------------------

outputTxt(" ");
outputTxt("Creating tasks.");

//创建任务
ksError = KS_createTask(
&pAppPtr->hTaskB_, // Address of task handle,任务句柄
hCallbackB, // Callback handle,回调函数
250, // Priority,优先级
KSF_DONT_START); // Flags, don‘t start now,标志位,不立即启动
//任务句柄存入共享内存结构体中,任务执行的本质是执行hCallbackB回调函数
//优先级为250(数值越大优先级越高)
//以下两个任务的创建过程与本例相似,但是优先级不同
if (ksError != KS_OK) {
outputErr(ksError, "KS_createTask", "Failed to create task");
KS_closeDriver();
return;
}

ksError = KS_createTask(
&pAppPtr->hTaskC_, // Address of task handle
hCallbackC, // Callback handle
150, // Priority
KSF_DONT_START); // Flags, don‘t start now
if (ksError != KS_OK) {
outputErr(ksError, "KS_createTask", "Failed to create task");
KS_closeDriver();
return;
}

ksError = KS_createTask(
&pAppPtr->hTaskA_, // Address of task handle
hCallbackA, // Callback handle
200, // Priority
0); // Flags, start immediately立即启动
if (ksError != KS_OK) {
outputErr(ksError, "KS_createTask", "Failed to create task");
KS_closeDriver();
return;
}

waitTime(1000 * ms);//延时1s,等待3个任务都执行完毕

outputTxt(" ");
outputTxt("The tasks completed their work.");

char pBuf[10];
int length;
KS_getPipe(//读取pipe数据到pBuf中
pAppPtr->hPipe_, // Pipe handle
pBuf, // Pointer to buffer
9, // Buffer size
&length, // Pointer to int to write gotten length
0); // Flags
pBuf[length] = 0;

outputTxt("Expected output : ABBBCBBAC");
outputTxt("Actual output : ", false);
outputTxt(pBuf);//打印pBuf中的字符串
outputTxt(" ");

//三个回调函数

首先TaskA运行,TaskA激活TaskB,由于TaskB优先级比TaskA高,因此TaskB运行

然后TaskB挂起TaskA,激活TaskC,然后挂起自身,此时只有低优先级的TaskC可以执行

然后TaskC激活TaskB,TaskB优先级比TaskC高,此时TaskB执行,然后激活TaskA,但是TaskA优先级比TaskB低因此不会被立即执行

TaskB执行完毕之后,由于TaskA优先级比TaskC高,此时TaskA执行

TaskA执行完毕之后,TaskC执行,最后三个任务都执行完成。

等待1s后,打印输出任务执行过程中向pipe写入的数据“ABBBCBBAC”


//------ _callBackA ------
static Error __stdcall _callBackA(void* pArgs, void* pContext) {
CallBackData* pData = (CallBackData*)pArgs;

const char chr = ‘A‘;

KS_putPipe(//向pipe中写入‘A‘
pData->hPipe_, // Pipe handle
&chr, // Address of packet
1, // One item
NULL, // Number of bytes transmitted
0); // Flags, here none

KS_triggerTask(//激活任务b,由于b优先级比a高,调到b中执行
pData->hTaskB_); // Task handle

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//写入‘a’

KS_exitTask(//退出当前任务,此时a,b都执行完毕,则调到c中执行
NULL, // Task handle, null for current task
0); // Exit code

return KS_OK;
}

//------ _callBackB ------
static Error __stdcall _callBackB(void* pArgs, void* pContext) {
CallBackData* pData = (CallBackData*)pArgs;

const char chr = ‘B‘;

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//向pipe中写入‘B’

KS_triggerTask(//激活c,但是c优先级低,不能被执行
pData->hTaskC_); // Task handle

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//继续写入‘b’

KS_suspendTask(//将任务A挂起
pData->hTaskA_); // Task handle

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//继续写入‘b’

KS_suspendTask(//把自身挂起,即把b挂起,此时A也挂起,因此调到c中执行
NULL); // Task handle, null for current task

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//写入‘b’

KS_resumeTask(//恢复a
pData->hTaskA_); // Task handle

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//写入‘b‘

return KS_OK;//此时TaskB执行完毕,而a和c都处于就绪状态,而a优先级高于c,因此调到a中执行
}

//------ _callBackC ------
static Error __stdcall _callBackC(void* pArgs, void* pContext) {
CallBackData* pData = (CallBackData*)pArgs;

const char chr = ‘C‘;

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//向pipe中写入‘c’

KS_resumeTask(//激活TaskB,由于TaskB优先级比TaskC优先级高,调到TaskB中执行
pData->hTaskB_); // Task handle

KS_putPipe(pData->hPipe_, &chr, 1, NULL, 0);//写入‘c’

KS_exitTask(//退出任务,至此3个任务都执行完毕
NULL, // Task handle, null for current task
0); // Exit code

return KS_OK;
}

多任务编程----Kithara RTS工程源码解析

时间: 2024-08-02 02:49:04

多任务编程----Kithara RTS工程源码解析的相关文章

配置一个逻辑CPU专用于实时任务----Kithara RTS工程源码分析

本文以windows实时拓展Kithara RTS安装目录下的smp文件夹内的DedicatedRealTimeTask项目为例,讲解使实时任务以独占一个逻辑CPU的方式运行,并实现任务间的同步. 目前多核计算机已经普及,多数的PC都是多核的.针对这种多核结构,我们设想把计算机划分为不同的硬件区间,其中一部分用于被实时任务专用,另一部分是被windows使用的,两者之间互不干扰,这样实时任务可以实现更好的实时性能.这种硬件划分,一般是按照物理CPU的核心数,即逻辑CPU的数量来配置的.可以配置一

嵌入式linux开发uboot移植(二)——uboot工程源码目录分析

嵌入式linux开发uboot移植(二)--uboot工程源码目录分析 本文分析的uboot为uboot_smdkv210,是三星官方发布的基于S5PV210评估开发板对应的uboot. 一.uboot源码目录结构解析 1.cpu 本文件夹下的子文件与处理器相关,每个文件夹代表一种CPU系列.每个子目录中都包括cpu.c.interrupts.c.start.S文件. cpu.c主要用于初始化CPU.设置指令Cache和数据Cache等 interrupt.c主要用于设置系统的各种中断和异常 s

工程源码目录

以下资源全部为网络搜集所得,仅供学习研究,严谨用于商业行为,请下载后于24小时之内删除. 2-1    炉石传说 客户端加服务器端 链接:http://pan.baidu.com/s/1dDKY3Fr 密码:c03q 2-2    新仙剑奇侠传 链接:http://pan.baidu.com/s/1b4QVqI 密码:dic5 2-3    unity3d 战斗卡牌<变身吧主公>客户端+服务器源码 链接:http://pan.baidu.com/s/1kUpot51 密码:i02u 2-4  

Android Activity启动过程源码解析

背景 启动App内部的Activity,Android 6.0 系统概要 系统会为每个App创建一个进程,系统进程和App进程之间通过Binder通信    2个Binder接口 IActivityManager 和 IApplicationThread    几个Binder相关的类    ActivityManagerService extends ActivityManagerNative    ActivityManagerNative extends Binder implements

Redis的字典(dict)rehash过程源码解析

Redis的内存存储结构是个大的字典存储,也就是我们通常说的哈希表.Redis小到可以存储几万记录的CACHE,大到可以存储几千万甚至上亿的记录(看内存而定),这充分说明Redis作为缓冲的强大.Redis的核心数据结构就是字典(dict),dict在数据量不断增大的过程中,会遇到HASH(key)碰撞的问题,如果DICT不够大,碰撞的概率增大,这样单个hash 桶存储的元素会越来愈多,查询效率就会变慢.如果数据量从几千万变成几万,不断减小的过程,DICT内存却会造成不必要的浪费.Redis的d

Android网络编程(十一)源码解析Retrofit

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 Android网络编程(七)源码解析OkHttp前篇[请求网络] Android网络编程(八)源码解析OkHttp后篇[复用连接池] Andr

Unity3D工程源码目录

2-1    炉石传说 客户端加服务器端 链接:http://pan.baidu.com/s/1dDKY3Fr 密码:c03q 2-2    新仙剑奇侠传 链接:http://pan.baidu.com/s/1b4QVqI 密码:dic5 2-3    unity3d 战斗卡牌<变身吧主公>客户端+服务器源码 链接:http://pan.baidu.com/s/1kUpot51 密码:i02u 2-4    降临OL-U3D全套源码 链接:http://pan.baidu.com/s/1skt

Android网络编程(七)源码解析OkHttp前篇[请求网络]

相关文章 Android网络编程(一)HTTP协议原理 Android网络编程(二)HttpClient与HttpURLConnection Android网络编程(三)Volley用法全解析 Android网络编程(四)从源码解析volley Android网络编程(五)OkHttp2.x用法全解析 Android网络编程(六)OkHttp3用法全解析 前言 学会了OkHttp3的用法后,我们当然有必要来了解下OkHttp3的源码,当然现在网上的文章很多,我仍旧希望我这一系列文章篇是最简洁易懂

neutron ml2 network创建流程源码解析

Neutron的整体架构分为三层. Server —> plugin —>agent 启动server之后neutron会将请求路径和对应的处理函数进行映射. 具体的处理函数由plugin来提供,plugin做的事情有两个: 1)在数据库中创建资源 2)发送rpc请求到具体的agent 所有的plugin提供统一的接口,包括核心资源的增删改查. neutron原生提供ml2这一plugin,ml2plugin分为类型驱动和机制驱动. 下面从创建network的角度来看一下neutron的整个调