
清空记录
历史记录
取消
清空记录
历史记录

编程入门[Hello,OpenHarmony]
#include
#include "ohos_init.h"
void hello(void){
printf("Hello,OpenHarmony!");
}
SYS_RUN(hello);
第一次操作的伙伴们可能会在引入”ohos_init.h“库时报错,面对这个问题我们只需要修改我们的include path即可,一般我们直接在目录下的 .vscode/c_cpp_properties.json文件中直接修改includePath
sudo apt install mlocate
sudo updatedb
locate ohos_init.h
找到我们源码根目录下 include路径下的ohos_init.h文件
static_library("sayHello"){
sources = [
"hello.c"
]
include_dirs = [
"//commonlibrary/utils_lite/include"
]
}
static_library表示我们编写的静态模块,名为"sayHello", sources表示我们要编译的源码,include_dirs表示我们引入的库,这里的双斜杠就代表我们的源码根目录,”/commonlibrary/utils_lite/include“就是我们ohos_init.h的所在目录
这表示我们的程序将会执行hello_demo样例中的sayHello模块
至此编码完成了编码入门,下面就具体介绍OpenHarmony的内核编程。
内核
我们可以看到最底层叫做内核层,有Linux,LiteOS等。内核在整个架构,或者操作系统中起到一个核心作用,他负责管理计算机系统内的资源和硬件设备,提供给顶层的应用层一个统一规范的接口,从而使得整个系统能够完成应用与硬件的交互。
这些都是进程,一个进程又由多个线程组成。那么CPU,内存,硬盘,网络这些硬件层面资源是怎么合理分配到我们软件的各个进程中呢?这就是内核帮助我们完成的事情,我们并不关心我们设备上的应用在哪里执行,如何分配资源,内核会完成这些事情。我们日常与软件交互,而内核会帮助我们完成软件和硬件的交互。
下面重点介绍KAL抽象层 和 基础内核的操作
内核编程
typedef struct {
/** Thread name */
const char *name;
/** Thread attribute bits */
uint32_t attr_bits;
/** Memory for the thread control block */
void *cb_mem;
/** Size of the memory for the thread control block */
uint32_t cb_size;
/** Memory for the thread stack */
void *stack_mem;
/** Size of the thread stack */
uint32_t stack_size;
/** Thread priority */
osPriority_t priority;
/** TrustZone module of the thread */
TZ_ModuleId_t tz_module;
/** Reserved */
uint32_t reserved;
} osThreadAttr_t;
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
osStatus_t osThreadTerminate (osThreadId_t thread_id);
typedef enum {
/** Operation completed successfully */
osOK = 0,
/** Unspecified error */
osError = -1,
/** Timeout */
osErrorTimeout = -2,
/** Resource error */
osErrorResource = -3,
/** Incorrect parameter */
osErrorParameter = -4,
/** Insufficient memory */
osErrorNoMemory = -5,
/** Service interruption */
osErrorISR = -6,
/** Reserved. It is used to prevent the compiler from optimizing enumerations. */
osStatusReserved = 0x7FFFFFFF
} osStatus_t;
回调函数怎么写?当然是结合我们的任务,每间隔0.1秒,输出“Hello,OpenHarmony”,1秒后终止。讲到这里,代码的整体逻辑是不是就清晰了很多,直接上完整代码。
#include
#include "ohos_init.h"
// CMSIS
#include "cmsis_os2.h"
// POSIX
#include
// 线程回调函数
void printThread(void *args){
(void)args;
while(1){
printf("Hello,OpenHarmony!\r\n");
// 休眠0.1秒
osDelay(10);
}
}
void threadTest(void){
// 创建线程
osThreadAttr_t attr;
attr.name = "mainThread";
// 线程
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024;
attr.priority = osPriorityNormal;
// 将线程启动
osThreadId_t tid = osThreadNew((osThreadFunc_t)printThread, NULL, &attr);
if(tid == NULL){
printf("[Thread Test] Failed to create printThread!\r\n");
}
// 休眠5秒
osDelay(500);
// 终止线程
osStatus_t status = osThreadTerminate(tid);
printf("[Thread Test] printThread stop, status = %d.\r\n", status);
}
APP_FEATURE_INIT(threadTest);
static_library("thread_demo"){
sources = [
"singleThread.c"
]
include_dirs = [
"//commonlibrary/utils_lite/include",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}
注意的是,这次的写法与上次不同,是因为笔者的样例文件名和静态模块的名字是一样的就可以简写。
osThreadId_t newThread(char *name, osThreadFunc_t func, void *arg){
// 定义线程和属性
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0
};
// 创建线程
osThreadId_t tid = osThreadNew(func, arg, &attr);
if(tid == NULL){
printf("[newThread] osThreadNew(%s) failed.\r\n", name);
}
return tid;
}
线程部分先体会到这里,想要探索更过线程相关的API,笔者这里提供了API网站,供大家参考学习。
软件定时器
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
typedef enum {
/** One-shot timer */
osTimerOnce = 0,
/** Repeating timer */
osTimerPeriodic = 1
} osTimerType_t;
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);
osStatus_t osTimerStop (osTimerId_t timer_id);
osStatus_t osTimerDelete (osTimerId_t timer_id);
#include
#include "ohos_init.h"
// CMSIS
#include "cmsis_os2.h"
// POSIX
#include
// 为操作软件的时间
static int times = 0;
// 软件定时器回调函数
void timerFunction(void){
times++;
printf("[Timer Test] Timer is Running, times = %d.\r\n", times);
}
// 主函数
void timerMain(void){
// 创建软件定时器
osTimerId_t tid = osTimerNew(timerFunction, osTimerPeriodic, NULL, NULL);
if(tid == NULL){
printf("[Timer Test] Failed to create a timer!\r\n");
return;
} else {
printf("[Timer Test] Create a timer success!\r\n");
}
// 启动软件定时器,每1秒执行一次回调函数
osStatus_t status = osTimerStart(tid, 100);
// 当超过三个周期位操作软件时,关闭软件
while(times <= 3){
osDelay(100);
}
// 停止软件定时器
status = osTimerStop(tid);
// 删除软件定时器
status = osTimerDelete(tid);
printf("[Timer Test] Time Out!\r\n");
}
void TimerTest(void){
// 创建测试线程
osThreadAttr_t attr;
attr.name = "timerMain";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 0U;
attr.priority = osPriorityNormal;
// 启动测试线程
osThreadId_t tid = osThreadNew((osThreadFunc_t)timerMain, NULL, &attr);
if(tid == NULL){
printf("[Timer Test] Failed to created timerMain!\r\n");
}
}
APP_FEATURE_INIT(TimerTest);
static_library("timer_demo"){
sources = [
"timer.c"
]
include_dirs = [
"//commonlibrary/utils_lite/include",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}
typedef struct {
const char *name;
uint32_t attr_bits;
void *cb_mem;
uint32_t cb_size;
void *stack_mem;
uint32_t stack_size;
osPriority_t priority;
TZ_ModuleId_t tz_module;
uint32_t reserved;
} osThreadAttr_t;
osThreadId_t osThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr);
sStatus_t status = osThreadTerminate(osThreadId_t tid);
if(count > 0){
count--;
}
售票的逻辑很简单,只要票数大于零,还有票能卖,那就在此基础上减掉一。问题就在于,两个线程同时在count = 1的时候通过了if判断,都执行的count--;那么就会出现了count = -1,也就是票数为负 的bug结果。
typedef struct {
/** Mutex name */
const char *name;
/** Reserved attribute bits */
uint32_t attr_bits;
/** Memory for the mutex control block */
void *cb_mem;
/** Size of the memory for the mutex control block */
uint32_t cb_size;
} osMutexAttr_t;
osMutexId_t osMutexNew(const osMutexAttr_t *attr);
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout);
传入互斥锁id,设置我们的延迟时间,当线程获取到我们的互斥锁时,返回的状态是osOK。
typedef enum {
/** Operation completed successfully */
osOK = 0,
/** Unspecified error */
osError = -1,
/** Timeout */
osErrorTimeout = -2,
/** Resource error */
osErrorResource = -3,
/** Incorrect parameter */
osErrorParameter = -4,
/** Insufficient memory */
osErrorNoMemory = -5,
/** Service interruption */
osErrorISR = -6,
/** Reserved. It is used to prevent the compiler from optimizing enumerations. */
osStatusReserved = 0x7FFFFFFF
} osStatus_t;
osStatus_t osMutexRelease(osMutexId_t mutex_id);
当我们的线程执行完业务后需要把锁释放出来,让别的线程获取锁,执行业务。当然这个过程是线程之间的竞争,一个线程可能一直得不到锁,一个线程也可能刚释放锁又获得锁,我们可以添加休眠操作,提高锁在各个线程间的分配。
#include
#include
#include "ohos_init.h"
#include "cmsis_os2.h"
// 模拟动物园门票数
static int count = 100;
// 售票业务线程
void outThread(void *args){
// 获取互斥锁
osMutexId_t *mid = (osMutexId_t *)args;
// 每个线程都在不停地买票
while(1){
// 获取锁,进入业务流程
if(osMutexAcquire(*mid, 100) == osOK){
if(count > 0){
count--;
// 设置提示信息
printf("[Mutex Test] Thread %s get a value, the less is %d.\r\n", osThreadGetName(osThreadGetId()), count);
} else {
// 告知这些线程已经没有门票卖了,线程结束
printf("[Mutex Test] The value is out!\r\n");
osThreadTerminate(osThreadGetId());
}
}
// 释放锁
osMutexRelease(*mid);
osDelay(5);
}
}
// 创建线程封装
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主函数实现多线程的创建,执行买票业务
void mutexMain(void){
// 创建互斥锁
osMutexAttr_t attr = {0};
// 获取互斥锁的id
osMutexId_t mid = osMutexNew(&attr);
if(mid == NULL){
printf("[Mutex Test] Failed to create a mutex!\r\n");
}
// 创建多线程
osThreadId_t tid1 = createThreads("Thread_1", (osThreadFunc_t)outThread, &mid);
osThreadId_t tid2 = createThreads("Thread_2", (osThreadFunc_t)outThread, &mid);
osThreadId_t tid3 = createThreads("Thread_3", (osThreadFunc_t)outThread, &mid);
osDelay(1000);
}
// 测试线程
void MainTest(void){
osThreadId_t tid = createThreads("MainTest", (osThreadFunc_t)mutexMain, NULL);
}
APP_FEATURE_INIT(MainTest);
static_library("mutex_demo"){
sources = [
"mutex.c"
]
include_dirs = [
"//commonlibrary/utils_lite/include",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis"
]
}
结果展示
if(osMutexAcquire(*mid, 100) == osOK){
if(count > 0){
count--;
printf("[Mutex Test] Thread %s get a value, the less is %d.\r\n", osThreadGetName(osThreadGetId()), count);
} else {
printf("[Mutex Test] The value is out!\r\n");
osThreadTerminate(osThreadGetId());
}
}
结果展示如下:
osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout);
#define osWaitForever 0xFFFFFFFFU
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id);
3.源码编写
#include
#include
#include "ohos_init.h"
#include "cmsis_os2.h"
// 售票口 4
#define OUT_NUM 4
// 检票口 2
#define IN_NUM 2
// 信号量
osSemaphoreId_t sid;
// 待检票人数
static int people = 0;
// 售票业务
void outThread(void *args){
// 获取互斥锁
osMutexId_t *mid = (osMutexId_t *)args;
while(1){
if(osMutexAcquire(*mid, 100) == osOK){
// 卖一张票,带检票的人数就会加一位
people++;
printf("[SEMAPHORE TEST] out, people: %d.\r\n", people);
}
osMutexRelease(*mid);
osDelay(50);
}
}
// 检票业务
void inThread(void *args){
// 获取信号量
osSemaphoreAcquire(sid, osWaitForever);
while(1){
if(people > 0){
people--;
printf("[SEMAPHORE TEST] in, people: %d.\r\n", people);
}
osSemaphoreRelease(sid);
osDelay(100);
}
}
// 创建线程封装
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024 * 2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主线程
void SemaphoreMain(void){
// 创建信号量
sid = osSemaphoreNew(IN_NUM, IN_NUM, NULL);
// 创建互斥锁
osMutexAttr_t attr = {0};
// 获取互斥锁的id
osMutexId_t mid = osMutexNew(&attr);
// 创建售票线程
for(int i = 0; i < OUT_NUM; i++){
createThreads("", (osThreadFunc_t)outThread, &mid);
}
// 创建检票线程
for(int i = 0; i < IN_NUM; i++){
createThreads("", (osThreadFunc_t)inThread, NULL);
}
}
// 测试函数
void MainTest(){
createThreads("MainTest", (osThreadFunc_t)SemaphoreMain, NULL);
}
APP_FEATURE_INIT(MainTest);
static_library("semaphore_demo"){
sources = [
"semaphore.c"
]
include_dirs = [
"//utils/native/lite/include",
]
}
#### 消息队列API
osMessageQueueId_t osMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr);
osStatus_t osMessageQueuePut (osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout);
osStatus_t osMessageQueueGet (osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout);
osStatus_t osMessageQueueDelete (osMessageQueueId_t mq_id);
3.编写源码
#include
#include
#include "ohos_init.h"
#include "cmsis_os2.h"
// 定义消息队列的大小
#define QUEUE_SIZE 15
// 定义请求数量
#define REQ_SIZE 10
// 定义消息的结构
typedef struct{
osThreadId_t tid;
} message_queue;
// 创建消息队列id
osMessageQueueId_t qid;
// 模拟发送业务
void sendThread(void){
// 定义一个消息结构
message_queue sentry;
sentry.tid = osThreadGetId();
osDelay(100);
// 消息入队
osMessageQueuePut(qid, (const void*)&sentry, 0, osWaitForever);
// 设置提示信息
printf("[MESSAGEQUEUE TEST] %d send a message.\r\n", sentry.tid);
}
// 模拟处理业务
void receiverThread(void){
// 定义一个消息结构
message_queue rentry;
int less = 5;
while(less > 0){
osMessageQueueGet(qid, (void *)&rentry, NULL, osWaitForever);
less--;
printf("[MESSAGEQUEUE TEST] %d get a product, less = %d.\r\n", rentry.tid, less);
osDelay(5);
}
printf("[MESSAGEQUEUE TEST] over!\r\n");
}
// 创建线程封装
osThreadId_t createThreads(char *name, osThreadFunc_t func, void *args){
osThreadAttr_t attr = {
name, 0, NULL, 0, NULL, 1024 * 2, osPriorityNormal, 0, 0
};
osThreadId_t tid = osThreadNew(func, args, &attr);
return tid;
}
// 主线程
void MessageQueueMain(void){
// 创建一个消息队列
qid = osMessageQueueNew(QUEUE_SIZE, sizeof(message_queue), NULL);
// 创建发送线程
for(int i = 0; i < REQ_SIZE; i++){
createThreads("", (osThreadFunc_t)sendThread, NULL);
}
osDelay(5);
// 创建接收线程
createThreads("", (osThreadFunc_t)receiverThread, NULL);
osDelay(500);
// 删除消息队列
osMessageQueueDelete(qid);
}
// 测试函数
void MainTest(){
createThreads("MainTest", (osThreadFunc_t)MessageQueueMain, NULL);
}
APP_FEATURE_INIT(MainTest);
static_library("queue_demo"){
sources = [
"queue.c",
]
include_dirs = [
"//utils/native/lite/include",
]
}
结束语
