往期知识点记录:
一、前言
本文针对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🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请看下图提示: