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

第四章 同步模块

4.1 信号量(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);

4.1.1 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代码如下:
/* ======== semtest.c ======== */
#include <xdc/std.h>
#include <xdc/runtime/Memory.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Queue.h>
#define NUMMSGS  3  /* number of messages */
#define NUMWRITERS  3  /* number of writer tasks created with */
/* Config Tool */
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是队列,尾进头出,这个简单的数据结构的知识我就不哆嗦了。
个人感觉这个例子写得不是太好,为何要用两个队列来完成这项功能,我看了半天还是无法完全理解作者意图。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值