OpenHarmony POSIX和CMSIS接口适配层解读adapter(2):thread/memory/time

往期知识点记录:

一、前言

本文针对thread_adapter、memory_adapter、time_adapter部分进行解读,也是samgr/adapter下关于POSIX和CMSIS的最后一部分代码。

二、头文件分析

  • thread_adapter
    在samgr\adapter\thread_adapter.h中对线程的操作进行声明。
typedef void *(*Runnable)(void *argv);     //函数指针
typedef struct ThreadAttr ThreadAttr;
struct ThreadAttr {
    const char *name;   // name of the thread  线程名
    uint32 stackSize;   // size of stack       栈大小
    uint8 priority;     // initial thread priority 优先级
    uint8 reserved1;    // reserved1 (must be 0)  预留
    uint16 reserved2;   // reserved2 (must be 0)
};
MutexId MUTEX_InitValue(void);//申请锁
void MUTEX_Lock(MutexId mutex);//加锁
void MUTEX_Unlock(MutexId mutex);//解锁
//保障计算进程中创建线程个数的线程安全
void MUTEX_GlobalLock(void);//加锁
void MUTEX_GlobalUnlock(void);//解锁
ThreadId THREAD_Create(Runnable run, void *argv, const ThreadAttr *attr);//创建线程
int THREAD_Total(void);//获取线程总数
void *THREAD_GetThreadLocal(void);//获取线程存储的值
void THREAD_SetThreadLocal(const void *local);//记录local值
  • memory_adapter

在samgr\adapter\memory_adapter.h中对分配内存的操作进行声明。

void *SAMGR_Malloc(uint32 size);//分配size大小的内存
void SAMGR_Free(void *buffer);//释放buffer指向的缓冲区
  • time_adapter

在samgr\adapter\time_adapter.h中对时间相关的操作进行声明。

int32 WDT_Start(uint32 ms);//开始
int32 WDT_Reset(uint32 ms);//重置
int32 WDT_Stop(void);//停止
uint64 SAMGR_GetProcessTime(void);//获取时间

三、函数实现分析

在samgr\adapter\posix\thread_adapter.c中实现POSIX的线程操作。

#define PRI_BUTT 39
#define MIN_STACK_SIZE 0x8000
static int g_threadCount = 0;                              //记录线程数,注意在线程被释放的时候应减1
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化锁,用于保障当前进程线程数量的计数
static pthread_key_t g_localKey = -1;                      //类似线程的全局变量
static pthread_once_t g_localKeyOnce = PTHREAD_ONCE_INIT;  //保障pthread_once中调用的函数只执行一次
//申请一个已初始化的锁
MutexId MUTEX_InitValue()
{
    //分配内存
    pthread_mutex_t *mutex = SAMGR_Malloc(sizeof(pthread_mutex_t));
    if (mutex == NULL) {
        return NULL;
    }
    //初始化锁
    (void)pthread_mutex_init(mutex, NULL);
    return (MutexId)mutex;
}
//加锁
void MUTEX_Lock(MutexId mutex)
{
    if (mutex == NULL) {
        return;
    }
    pthread_mutex_lock((pthread_mutex_t *)mutex);
}
//解锁
void MUTEX_Unlock(MutexId mutex)
{
    if (mutex == NULL) {
        return;
    }
    pthread_mutex_unlock((pthread_mutex_t *)mutex);
}
//加锁
void MUTEX_GlobalLock(void)
{
    pthread_mutex_lock(&g_mutex);
}
//解锁
void MUTEX_GlobalUnlock(void)
{
    pthread_mutex_unlock(&g_mutex);
}
static void KeyCreate()
{
    //调用pthread_key_create()
    //所创建的g_localKey都是所有线程可访问的,各个线程可根据自己的需要往g_localKey中填入不同的值
    //第二个参数是一个清理函数,用来在线程释放该线程存储的时候被调用,NULL即调用默认的清理函数
    (void) pthread_key_create(&g_localKey, NULL);
}
//返回线程总数
int THREAD_Total(void)
{
    return g_threadCount;
}
//取出线程存储在g_localKey中的值
void *THREAD_GetThreadLocal(void)
{
    return pthread_getspecific(g_localKey);
}
//线程将local存储在g_localKey中
void THREAD_SetThreadLocal(const void *local)
{
    pthread_setspecific(g_localKey, local);
}

POSIX创建线程的操作

/*
    函数功能:创建线程
    函数参数:
        @run:创建的线程开始运行的函数地址
        @argv:运行函数需要的参数
        @attr:线程属性
    函数返回:
        若成功则返回创建的线程ID,否则返回NULL
    详细:
        1.根据参数attr设置线程堆栈大小,静态优先级
        2.设置线程调度策略为轮循式调度
        3.pthread_once指定的函数KeyCreate只在第一次被调用时执行
        4.调用pthread_create,根据线程属性threadAttr创建线程,并返回线程ID threadId
        5.线程执行的函数为run,参数为argv
        6.线程数+1
*/
ThreadId THREAD_Create(Runnable run, void *argv, const ThreadAttr *attr)
{
    pthread_attr_t threadAttr;      //线程属性
    pthread_attr_init(&threadAttr); //初始化
    pthread_attr_setstacksize(&threadAttr, (attr->stackSize | MIN_STACK_SIZE));//设置线程堆栈大小
#ifdef SAMGR_LINUX_ADAPTER
    struct sched_param sched = {attr->priority};
#else
    struct sched_param sched = {PRI_BUTT - attr->priority};
#endif
    //设置线程是否继承父线程调度策略
    pthread_attr_setinheritsched(&threadAttr, PTHREAD_EXPLICIT_SCHED);//PTHREAD_EXPLICIT_SCHED:不继承,只有不继承父线程的调度策略才可以设置线程的调度策略
    //设置线程的调度策略
    pthread_attr_setschedpolicy(&threadAttr, SCHED_RR);//SCHED_RR:轮询式调度
    //设置静态优先级
    pthread_attr_setschedparam(&threadAttr, &sched);
    (void) pthread_once(&g_localKeyOnce, KeyCreate);//使用互斥锁和条件变量保证由pthread_once()指定的函数执行且仅执行一次
    pthread_t threadId = 0;
    //创建线程
    int errno = pthread_create(&threadId, &threadAttr, run, argv);
    if (errno != 0) {
        return NULL;
    }
    MUTEX_GlobalLock();
    g_threadCount++;//线程数+1
    MUTEX_GlobalUnlock();
    return (ThreadId)threadId;
}

在samgr\adapter\cmsis\thread_adapter.c中实现CMSIS的线程操作。

extern void *osThreadGetArgument(void);
//申请锁
MutexId MUTEX_InitValue()
{
    //创建并初始化一个互斥锁
    return osMutexNew(NULL);
}
//加锁
void MUTEX_Lock(MutexId mutex)
{
    if (mutex == NULL)
    {
        return;
    }
    // 阻塞函数 osMutexAcquire 一直等待,直到由参数 mutex_id 指定的互斥锁对象变为可用。
    // 当超时设置为 osWaitForever 时,该函数将等待无限时间,直到互斥锁变为可用。
    osMutexAcquire(mutex, osWaitForever);
}
//解锁
void MUTEX_Unlock(MutexId mutex)
{
    if (mutex == NULL)
    {
        return;
    }
    //释放由参数 mutex_id 指定的互斥锁,当前等待此互斥锁的其他线程将进入 READY 状态
    osMutexRelease(mutex);
}
void MUTEX_GlobalLock(void)
{
    //osKernelLock Allow all task switches to be locked
    //它返回先前锁定状态的值(如果锁定,则返回1;如果未锁定,则返回0);负数表示错误码
    osKernelLock();
}
void MUTEX_GlobalUnlock(void)
{
    //osKernelUnlock From osKernelLock restore.
    osKernelUnlock();
}
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};
    /*
        函数功能:创建线程
        函数参数:
            @param1:回调函数的入口
            @param2:传递给线程的参数
            @param3:线程属性
        函数返回:返回线程ID or 出错的情况下返回NULL
    */
    return (ThreadId)osThreadNew((osThreadFunc_t)run, argv, &taskAttr);
}
int THREAD_Total(void)
{
    //获取活动线程的数量
    return osThreadGetCount();
}
void *THREAD_GetThreadLocal(void)
{
    //返回Parameter
    return osThreadGetArgument();
}
void THREAD_SetThreadLocal(const void *local)
{
    (void)local;
}
  • memory_adapter

在samgr\adapter\posix\memory_adapter.c中实现POSIX的分配内存操作。在samgr\adapter\cmsis\memory_adapter.c中实现CMSIS的分配内存操作。这部分实现的细节是一致的,主要的区别在于头文件的引用不同。在POSIX下引用stdlib.h,在CMSIS下引用malloc.h。

void *SAMGR_Malloc(uint32 size)
{
    if (size == 0) {
        return NULL;
    }
    return malloc(size);//申请内存
}
void SAMGR_Free(void *buffer)
{
    if (buffer == NULL) {
        return;
    }
    (void)free(buffer);//释放内存
}
  • time_adapter

POSIX和CMSIS在time_adapter部分,代码仅在获取时间上不一致。
POSIX如下:

uint64 SAMGR_GetProcessTime(void)
{
    struct timespec ts = {0, 0};
    //获取时间
    clock_gettime(CLOCK_REALTIME, &ts);//CLOCK_REALTIME:a system-wide realtime clock
    return ((ts.tv_sec * MS_PER_SECOND) + (ts.tv_nsec / NS_PER_MS));//返回时间的单位为ms
}

CMSIS如下:

uint64 SAMGR_GetProcessTime(void)
{
    uint32 tick = osKernelGetTickCount();//RTOS kernel current tick count
    uint32 ticksPerSecond = osKernelGetTickFreq();//frequency of the kernel tick in hertz. kernel ticks per second.
    if (ticksPerSecond == 0) {
        return 0;
    }
    return (uint64)tick * MS_PER_SECOND / ticksPerSecond;//返回ms
}

四、总结

在adapter部分对POSIX和CMSIS在队列、线程、内存、时间方面进行统一的接口声明,并进行不同环境下的具体实现,保障OpenHarmony移植性。### 写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请看下图提示:
    在这里插入图片描述
  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值