参考文献:file:///D:/CCS/CC1310/simplelink_cc13x0_sdk_2_20_00_38/docs/ti154stack/html/tirtos/synchronization.html
本文章是基于上述TI官方手册的一些重点内容,鉴于笔者水平有限,只是摘录了一些内容。若有错误的地方,欢迎大家指出。详细资料请大家自行查看手册。与君共勉!
线程同步机制
TI-RTOS内核提供了几种任务同步的模块,例如信号量,事件和队列。
一、信号量
1. 概述
(1)应用
信号量通常用来进行任务的同步和互斥。也可以说是维持不同任务对共享资源的访问秩序。
图1 信号量功能
(2)分类
分类 | 描述 |
---|---|
计算型信号量 | 1. 记录信号量发布的次数(Semaphore_post()产生) 2. 适用于多任务间的多份共享资源的调度 3. 任务可等待可用资源(通过调用Semaphore_pend()产生) |
二值型信号量 | 1. 记录信号量是否发布(Semaphore_post()产生) 2. 适用于多任务间的一份共享资源的调度 |
计算型信号量 | 二值型信号量 | |
---|---|---|
计数范围 | 0~2^16(非负整数) | 0或1 |
2. 使用方法
(1)初始化
i)Creating
Semaphore_Handle sem;
Semaphore_Params semParams;
Semaphore_Params_init(&semParams);
sem = Semaphore_create(0, &semParams, NULL); // 内存在这里分配
if (sem == NULL) // 检查返回的句柄是否有效
{
System_abort("Semaphore could not be created");
}
ii)Constructing
Semaphore_Handle sem;
Semaphore_Params semParams;
Semaphore_Struct structSem; // 内存在这里分配
Semaphore_Params_init(&semParams);
Semaphore_construct(&structSem, 0, &semParams);
// 是否存储句柄可按需要选则
sem = Semaphore_handle(&structSem);
iii)区别
两种方式的区别在于内存分配以及内存分配错误处理。
(2)Pending a Semaphore
bool isSuccessful;
uint32_t timeout = 1000 * (1000/Clock_tickPeriod);
/* 挂起大约1s */
isSuccessful = Semaphore_pend(sem, timeoutInTicks);
if (isSuccessful)
System_printf("Semaphore was posted");
else
System_printf("Semaphore timed out");
注意:
默认的TI-RTOS系统滴答周期为1毫秒。通过在文件 .cfg 中设置 Clock.tickPeriod = 10,将此默认值重新配置为CC13x0的10微秒。
对于给定10微秒的系统滴答,timeout在上述代码中将是大约1秒。
(3)Posting a Semaphore
Semaphore_post(sem);
被阻塞的任务在信号量发布之后会从阻塞状态变成就绪状态。如果没有优先级更高的任务就绪,先前挂起的任务就会继续执行;如果没有任务被挂起,信号量发布将增加计数count。
二、事件
1. 概述
信号量提供了线程之间的基本同步。有时候,只有信号量足以了解什么进程需要被触发。但通常也需要跨线程传递同步信号的特定起因。这时可以使用TI-RTOS的事件模块。
(1)应用
每一个事件实际上包含了一个信号量。使用事件的附加优势在于可以以线程安全的方式向任务通知特定事件。
2. 使用方法
(1)初始化事件
与信号量类似,事件的初始化同样也存在 Creating 和 Constructing 两种方式。
Event_Handle event;
Event_Params eventParams;
Event_Struct structEvent; // 内存在编译时分配
Event_Params_init(&eventParams);
Event_construct(&structEvent, 0, &eventParams);
/* 可根据需要选择是否存储句柄 */
event = Event_handle(&structEvent);
(2)Pending on an Event
#define START_ADVERTISING_EVT Event_Id_00
#define START_CONN_UPDATE_EVT Event_Id_01
#define CONN_PARAM_TIMEOUT_EVT Event_Id_02
void TaskFxn(..)
{
/* 已发布事件的本地复制 */
uint32_t events;
while(1)
{
/* 等待某一事件被发布 */
events = Event_pend(event,
Event_Id_NONE,
START_ADVERTISING_EVT |
START_CONN_UPDATE_EVT |
CONN_PARAM_TIMEOUT_EVT,
BIOS_WAIT_FOREVER);
if (events & START_ADVERTISING_EVT)
{
// 处理
}
if (events & START_CONN_UPDATE_EVT)
{
// 处理
}
if (events & CONN_PARAM_TIMEOUT_EVT)
{
// 处理
}
}
}
(3)Posting an Event
#define START_ADVERTISING_EVT Event_Id_00
#define START_CONN_UPDATE_EVT Event_Id_01
#define CONN_PARAM_TIMEOUT_EVT Event_Id_02
void SwiFxn(UArg arg)
{
Event_post(event, START_ADVERTISING_EVT);
}