HarmonyOS鸿蒙Next开发实录:在Hi3861开发板上创建线程的三种方式
HarmonyOS鸿蒙Next开发实录:在Hi3861开发板上创建线程的三种方式 Hi3861上开发应用时推荐使用CMSIS标准的API,详细API查看api/api-LinkIoT/CMSIS.md · OpenHarmony/docs - Gitee.com
技术有限,如有错误还望不吝赐教。
基础:完成官方的快速入门教程
那天在看Hi3861的源码的时候发现在目录:
//project/vendor/hisi/hi3861/hi3861/platform/os/Huawei_LiteOS/components/lib/libc/musl/include
包含了musl的头文件,并且在编译脚本里面有此目录,难道Hi3861支持POSIX标准(Linux的API也遵循POSIX标准)?后来在kernel/标准库-0.md · OpenHarmony/docs - Gitee.com这一章中看到
OpenHarmony内核使用musl libc库,支持标准POSIX接口,开发者可基于POSIX标准接口开发内核之上的组件及应用。
我就以为应该支持的,但弄了挺久之后发现源码中只包含了这些API的头文件,并没有实现源码或者编译后的库,这就有点奇怪了。在gitee逛了挺久的,后来在readme/系统服务框架子系统README.md · OpenHarmony/docs - gitee.com中发现
M核:处理器架构为Cortex-M或同等处理能力的硬件平台,系统内存一般低于512KB,无文件系统或者仅提供一个可有限使用的轻量级文件系统,遵循CMSIS接口规范。
虽然Hi3861使用的是riscv架构(不是m核),但配置方面没达到Liteos-a的要求,所以系统还是liteos-m。那Hi3861应该时只支持CMSIS标准了,但不知道为什么源码里面包含了musl,不知道会不会是做了POSIX适配层,还没释放出来。
那既然是支持CMSIS标准,那就用CMSIS的API来创建一个线程吧,其实例程里面的LED灯demo就是使用CMSIS的。主要的代码:
osThreadAttr_t attr;
attr.name = "LedTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = LED_TASK_STACK_SIZE;
attr.priority = LED_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {
printf("[LedExample] Falied to create LedTask!\n");
}
创建一个osThreadAttr_t
结构体变量,这个结构体主要是包括了线程的各种参数,例如任务名,栈大小、优先级等等都是。然后使用osThreadNew
函数创建一个线程。
可以在
/kernel/liteos_m/components/cmsis/2.0
看一下osThreadNew
的实现源码
osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)
{
......
TSK_INIT_PARAM_S stTskInitParam;
......
stTskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST - ((UINT16)(attr->priority) - LOS_PRIORITY_WIN); /* 0~31 */
uwRet = LOS_TaskCreate(&uwTid, &stTskInitParam);
......
}
可以看到osThreadNew
调用的是最原生的Liteos API,从上面的代码可以看到,LiteOS的优先级和CMSIS的优先级不是一一对应的,转换关系看第三条代码,开发的时候需要注意一下。
那如果我们使用原生的代码创建线程(任务)会是怎样的呢:
TSK_INIT_PARAM_S stInitParam = {0};
stInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)LedTask;
stInitParam.usTaskPrio = LED_TASK_PRIO;
stInitParam.pcName = "LedTask";
stInitParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stInitParam.uwResved = LOS_TASK_STATUS_DETACHED;
if (LOS_TaskCreate(&s_uwTskID, &stInitParam) != LOS_OK) {
printf("Example_Task1 create Failed!\r\n");
}
其实大部分代码都差不多,只是需要注意的只是优先级不同。
LiteOS的原生API一般推荐写内核代码,不推荐用来写应用代码,但如果我们多看一下源码,其实里面很大一部分没使用LiteOS原生API也没使用CMSIS标准的API,而是使用了hi
开头的API。我在官方提供的Hi3861的api文档里面发现,里面的就是这一套API。比如,如果用这套API实现创建线程的话会是这样的:
hi_task_attr attr;
attr.stack_size = LED_TASK_STACK_SIZE; /* 800 */
attr.task_name = (hi_char*) "LedTask";
attr.task_prio = LED_TASK_PRIO; /* 28 */
hi_task_create(&g_test_flash_tb, &attr, LedTask, 0);
其实各套API代码内容都是差不多的。
我在源码里面并没有发现hi_task_create
的实现源码,这个应该是以库文件的形式存在的。有个问题是为什么已经有los API,还弄了一套hi API呢,我找的资料不够多,也可能是之前没有深入地了解过,还没找到这个答案。
那总共三套API,一般是开发应用层面使用CMSIS接口,内核则使用hi接口(其实我挺希望有POSIX的)。
其实还有一个有趣的地方,在文件中
/foundation/distributedschedule/services/samgr_lite/samgr/adapter/posix/thread_adapter.c
/foundation/distributedschedule/services/samgr_lite/samgr/adapter/cmsis/thread_adapter.c
分别对CMSIS和POSIX接口再封装了一层,例如:
ThreadId THREAD_Create(Runnable run, void *argv, const ThreadAttr *attr)
{
osThreadAttr_t taskAttr = {attr->name, 0, NULL, 0, NULL, attr->stackSize, attr->priority, 0, 0};
return (ThreadId)osThreadNew((osThreadFunc_t)run, argv, &taskAttr);
}
相当于用一个API接口适配了CMSIS和POSIX接口,那就意味着也同时适配了hi和los接口,那是不是说明以后还想再推一套API呢?但我现在能力有限,也对这部分代码并没有更多的了解,期待以后能知道更多。
作者:OSAaaa
你怎么懂的这么多呢
更多关于HarmonyOS鸿蒙Next开发实录:在Hi3861开发板上创建线程的三种方式的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
很值得一看
看上去不错
感谢楼主提点呀
这个挺不错的嘛
眼睛看了,但脑袋不会,嘻嘻
必须顶起来,好内容
我相当喜欢啦
坐等下一次直播课抽开发板
https://harmonyos.51cto.com/activity/19#hw
棒棒哒!!!!!棒棒哒!!!!!棒棒哒!!!!!棒棒哒!!!!!棒棒哒!!!!!棒棒哒!!!!!
在HarmonyOS鸿蒙Next中,在Hi3861开发板上创建线程的三种方式如下:
使用osThreadNew
函数
这是最直接的方式,通过调用osThreadNew
函数创建线程。该函数需要传入线程函数、线程参数、线程属性等。例如:
osThreadId_t threadId = osThreadNew(threadFunction, NULL, NULL);
使用osThreadCreate
函数
该函数与osThreadNew
类似,但需要手动设置线程属性。例如:
osThreadAttr_t threadAttr = {
.name = "MyThread",
.stack_size = 1024,
.priority = osPriorityNormal
};
osThreadId_t threadId = osThreadCreate(&threadAttr, threadFunction, NULL);
使用osThreadStatic
函数
该函数用于创建静态线程,线程的栈空间由用户预先分配。例如:
uint8_t threadStack[1024];
osThreadAttr_t threadAttr = {
.name = "MyStaticThread",
.stack_mem = threadStack,
.stack_size = sizeof(threadStack),
.priority = osPriorityNormal
};
osThreadId_t threadId = osThreadStatic(&threadAttr, threadFunction, NULL);
这三种方式均可在Hi3861开发板上创建线程,具体选择取决于应用场景和资源管理需求。
在HarmonyOS鸿蒙Next的Hi3861开发板上,创建线程主要有三种方式:
-
使用
osThreadNew
函数:这是最常用的方式,通过定义线程函数和属性,调用osThreadNew
来创建线程。例如:osThreadId_t threadId = osThreadNew(threadFunction, NULL, &threadAttr);
-
使用
osThreadCreate
函数:类似于osThreadNew
,但参数结构略有不同,适用于需要更细粒度控制的场景。osThreadId_t threadId = osThreadCreate(&threadDef, NULL);
-
使用
osThreadStaticNew
函数:适用于静态内存分配的场景,避免动态内存分配的开销。osThreadId_t threadId = osThreadStaticNew(threadFunction, NULL, &threadAttr, threadBuffer);
每种方式适用于不同的开发需求,开发者可根据具体场景选择合适的方法。