基于TI-RTOS的CC2650DK开发(11)---信号量

judy的头像

信号量(Semaphores)

SYS/BIOS在semaphores的基础上提供了一系列用于任务间同步和通信的函数。Semaphore通常用于协调访问一系列竞争任务间的共享资源。Semaphore模块提供的函数通过Semaphore_Handle类型句柄来操作semaphore对象的访问。参阅video introducing Semaphores进行概览。

无论是简单的(FIFO)或是优先级semaphores,Semaphore对象即可声明为计数semaphore,也可声明为二元semaphore。Semaphores可被用于task同步或互斥。相同的APIs可同时用于计数和二元semaphores。

默认情况下,semaphores是简单的计数semaphores。
计数semaphores保持一个相应可用资源内部计数的count。当count大于0,tasks在获取一个semaphore后将不再阻塞。semaphores的最大count值加1就是一个计数semaphore可协调的tasks的数量。
配置一个计数semaphore,按以下方式设置mode参数:
semParams.mode = Semaphore_Mode_COUNTING;

二元semaphores是可用或不可用的。它们的值不能超过1,因此,仅能用于不超过两个tasks的共享资源的协调访问。二元semaphores相对于计数semaphores来说,拥有更好的性能。
配置二元semaphores,设置mode参数如下:
semParams.mode = Semaphore_Mode_BINARY;

Tasks以FIFO顺序等待简单计数或二元semaphores无需关心任务的优先级。你也可以选择创建“优先级”semaphores以在等待列内中将等待tasks插入首个更低优先级的task之前。从而相同优先级的tasks以FIFO顺序等待,但高优先级tasks会在低优先级tasks之前被读取。

配置一个计数或二元优先级semaphore,使用以下常量之一配置mode参数:
semParams.mode = Semaphore_Mode_COUNTING_PRIORITY;
semParams.mode = Semaphore_Mode_BINARY_PRIORITY;

注意,使用优先级semaphores会在系统中增加中断延迟,因为当tasks列表在等待扫描适当插入点时会禁止中断。这通常是每一个等待任务的十几个指令。例如,如果有10个更高优先级tasks在等待,在新task加入列表前,会禁止中断以扫描所有10个tasks。

Semaphore_create()和Semaphore_delete() 函数分别用于创建和删除semaphore对象,你也可以使用以下代码静态地创建semaphore对象:
Semaphore_Handle Semaphore_create(
Int count,
Semaphore_Params *attrs
Error_Block *eb );
Void Semaphore_delete(Semaphore_Handle *sem);
semaphore在创建时初始化其count。通常count被设置为semaphore所同步的资源数量。

Semaphore_pend() 用于等待一个semaphore。如果semaphore count大于0,Semaphore_pend() 简单地减少count并返回。否则Semaphore_pend() 等待semaphore被Semaphore_post()提交。

下列代码所示的 Semaphore_pend()的timeout参数允许task等待直到超过timeout,无限期等待使用(BIOS_WAIT_FOREVER),或根本不等待用(BIOS_NO_WAIT)。Semaphore_pend()的返回值用于指示是否semaphore被成功捕获。
Bool Semaphore_pend(
Semaphore_Handle sem,
UInt timeout);

下列代码演示了Semaphore_post(),用于发送一个semaphore。如果一个task在等待semaphore,Semaphore_post()将移除semaphore队列的第一个task,并将其放入准备队列。如果没有tasks在等待,Semaphore_post()只是简单地增加semaphore count并返回。
Void Semaphore_post(Semaphore_Handle sem);

Semaphore示例

下例提供了简单代码用于三个写tasks创建唯一信息并将它们放至一个读task的列表中。写tasks调用Semaphore_post()来指示另一信息已经放入列表。读task调用Semaphore_pend()来等待信息。Semaphore_pend()仅在一个信息于列表中可用时返回。读task使用System_printf()函数打印信息。

此例中的三个写tasks,一个读task,一个semaphore和一个队列静态创建如下:
var Defaults = xdc.useModule('xdc.runtime.Defaults');
var Diags = xdc.useModule('xdc.runtime.Diags');
var Error = xdc.useModule('xdc.runtime.Error');
var Log = xdc.useModule('xdc.runtime.Log');
var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
var Main = xdc.useModule('xdc.runtime.Main');
var Memory = xdc.useModule('xdc.runtime.Memory')
var SysMin = xdc.useModule('xdc.runtime.SysMin');
var System = xdc.useModule('xdc.runtime.System');
var Text = xdc.useModule('xdc.runtime.Text');
var BIOS = xdc.useModule('ti.sysbios.BIOS');
var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
/* set heap and stack sizes */
BIOS.heapSize = 0x2000;
Program.stack = 0x1000;
SysMin.bufSize = 0x400;
/* set library type */
BIOS.libType = BIOS.LibType_Custom;
/* Set logger for the whole system */
var loggerBufParams = new LoggerBuf.Params();
loggerBufParams.numEntries = 32;
var logger0 = LoggerBuf.create(loggerBufParams);
Defaults.common$.logger = logger0;
Main.common$.diags_INFO = Diags.ALWAYS_ON;
/* Use Semaphore, and Task modules and set global properties */
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
Program.global.sem = Semaphore.create(0);
var Task = xdc.useModule('ti.sysbios.knl.Task');
Task.defaultStackSize = 512;
Task.idleTaskVitalTaskFlag = false;
/* Statically create reader and writer Tasks */
var reader = Task.create('&reader');
reader.priority = 5;
var writer0 = Task.create('&writer');
writer0.priority = 3;
writer0.arg0 = 0;
var writer1 = Task.create('&writer');
writer1.priority = 3;
writer1.arg0 = 1;
var writer2 = Task.create('&writer');
writer2.priority = 3;
writer2.arg0 = 2;
/* uses Queue module and create two instances statically */
var Queue = xdc.useModule('ti.sysbios.knl.Queue');
Program.global.msgQueue = Queue.create();
Program.global.freeQueue = Queue.create();

C代码如下:
基于TI-RTOS的CC2650DK开发(11)---信号量

typedef struct MsgObj
{
Queue_Elem elem; /* first field for Queue */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;
Void reader();
Void writer();
/* The following objects are created statically. */
extern Semaphore_Handle sem;
extern Queue_Handle msgQueue;
extern Queue_Handle freeQueue;
/* ======== main ======== */
Int main(Int argc, Char *argv[])
{
Int i;
MsgObj *msg;
Error_Block eb;
Error_init(&eb);
//这里注意,一个msg可容纳三个MsgObj结构体
msg = (MsgObj *) Memory_alloc(NULL, NUMMSGS * sizeof(MsgObj), 0, &eb);
if (msg == NULL)
{
System_abort("Memory allocation failed");
}
/* 把三个空消息msg压入freeQueue队列,则队列里总共可容纳9个MsgObj结构体 */
for (i = 0; i < NUMMSGS; msg++, i++)
{
Queue_put(freeQueue, (Queue_Elem *) msg);
}
BIOS_start();
return(0);
}
/* ======== reader ======== */
Void reader()
{
Msg msg;
Int i;
//循环9次读取msgQueue里的信息,每等到一个信号量读取一次
for (i = 0; i < NUMMSGS * NUMWRITERS; i++)
{
/* Wait for semaphore to be posted by writer(). */
Semaphore_pend(sem, BIOS_WAIT_FOREVER);
/* get message */
msg = Queue_get(msgQueue);
/* print value */
System_printf("read '%c' from (%d).\n", msg->val, msg->id);
/* free msg 压回去的意义何在?*/
Queue_put(freeQueue, (Queue_Elem *) msg);
}
System_printf("reader done.\n");
}
/* ======== writer ======== */
Void writer(Int id)
{
Msg msg;
Int i;
for (i = 0; i < NUMMSGS; i++)
{
/* 从freeQueue里出队一条信息,改造后压入msgQueue,然后
* 发信号量让reader接手处理信息,总共三条信息 */
msg = Queue_get(freeQueue);
/* fill in value */
msg->id = id;
msg->val = (i & 0xf) + 'a';
System_printf("(%d) writing '%c' ...\n", id, msg->val);
/* put message */
Queue_put(msgQueue, (Queue_Elem *) msg);
/* post semaphore */
Semaphore_post(sem);
}
System_printf("writer (%d) done.\n", id);
}

运行结果如下
[Cortex_M3_0] (0) writing 'a' ...
read 'a' from (0).
(0) writing 'b' ...
read 'b' from (0).
(0) writing 'c' ...
read 'c' from (0).
writer (0) done.
(1) writing 'a' ...
read 'a' from (1).
(1) writing 'b' ...
read 'b' from (1).
(1) writing 'c' ...
read 'c' from (1).
writer (1) done.
(2) writing 'a' ...
read 'a' from (2).
(2) writing 'b' ...
read 'b' from (2).
(2) writing 'c' ...
read 'c' from (2).
reader done.
writer (2) done.

此例一共三个writer,一个reader。writer的优先级列低,每次它向队列压一条信息然后发信号量,让reader接收处理信息,一共压三条信息后结束。由于有三个writer,所以最后处理了9条信息。Queue是队列,尾进头出,这个简单的数据结构的知识我就不哆嗦了。

转自: abatei博客