信号量(semaphore)是一个用来指示可用的资源并将可用资源的数量以数值的形式表示出来的对象。当使用一组资源时,信号量用来实现互斥控制和同步。uTenux提供了信号量出来的API,可以很方便地使用信号量。

uTenux中,信号量包含一个资源计数(用来指示是否存在相应的资源以及资源的数量)和一个等待信号量的任务队列。

当一个任务返回m个资源时,信号量资源计数加m。当一个任务获得n个资源时,信号量资源计数减n。如果信号量资源的数量不够(进一步减少信号量计数可能使其值变成负数),则尝试获取资源的任务进入等待状态,直至下次有资源返回。等待信号量资源的任务被置入信号量队列。

1、创建信号量:IDsemid=tk_cre_sem(T_CSEM*pk_csem);

T_CSEM为信号量结构体,定义如下:

typedef    struct t_csem {
VP exinf; /*扩展信息,OS不关心 */
ATR sematr; /* 信号量属性*/
INT isemcnt; /* 信号量初始计数 */
INT maxsem; /* 最大信号量数目 */
UB dsname[8]; /* Object name */
} T_CSEM;

信号量的属性可以用下面的表达式得到:

sematr:=(TA_TFIFO||TA_TPRI)|(TA_FIRST||TA_CNT)| [TA_DSNAME]

TA_TFIFO               任务按FIFO的顺序排队

TA_TPRI                任务按优先级顺序排队

TA_FIRST               队列中第一个任务最先获得资源

TA_CNT                请求越少的任务越先获得资源

TA_DSNAME         设定DS对象名

等待信号量的任务的排队顺序可以设置成TA_FIFO或TA_TPRI。TA_FIRST和TA_CNT设定了获取资源的先后顺序

2、tk_sig_sem用来释放信号量

    提供一个释放信号量的数目即可。如果没有超过最大信号量计数,释放后,信号量技术增加这个数目。

3、tk_wai_sem用来申请信号量。

关于信号的量申请:

如果一次需要获得多个信号量,但是信号量又不够。比如我需要3个信号量,但剩余的信号量只有1个。那么用tk_wai_sem申请信号量时候,不会改变信号量计数,然后开始等待其他信号量。

实验验证:

1、创建三个任务:任务A、B、C。其中任务A需要三个信号量,任务B需要4个信号量。任务A的优先级大于任务B。任务C为最低优先级的空闲任务。

2、创建任务后,先启动任务B,任务B先申请4个信号量。然后启动任务A。

3、由于任务A的优先级高于任务B,任务B被中断,任务A开始执行。由于系统中没有可用信号量,任务A申请信号量失败 进入等待状态。

4、之后回到任务B,任务B释放四个信号量。此时,系统中有足够的信号量供任务A使用,任务A被唤醒。继续执行。

5、任务A执行一次之后进入休眠,任务B开始执行。任务B申请并获得4个信号量,完成LED反转。之后释放信号量进入休眠。

6、两个任务都进入等待状态,任务C开始执行。任务C是一个死循环。用于防止OS没有正在运行的任务而退出。

实验代码如下:

//本实验中,信号量代表开发板上的是个LED
//任务B需要4个信号量,控制LED同时亮灭
//任务A需要3个信号量,控制LED1、2、3同时亮灭 #include "SemSample.h"
#include <dev/ts_devdef.h> void SemSampleTaskA(W stacd,VP exinf);
void SemSampleTaskB(W stacd,VP exinf);
void SemSampleTaskC(W stacd,VP exinf);
void SemSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID TaskID_C;
static ID semid; ER SemSample(void)
{
ER ercd = E_OK;
T_CTSK ctsk;
T_CSEM csem; ctsk.exinf = NULL;
ctsk.task = SemSampleTaskA;
ctsk.tskatr = TA_HLNG | TA_RNG0;
ctsk.stksz = 512;
ctsk.bufptr = NULL;
ctsk.itskpri = 24;
TaskID_A = tk_cre_tsk(&ctsk);
if(TaskID_A< E_OK)
{
ercd = TaskID_A;
return ercd;
} ctsk.itskpri = 26;
ctsk.stksz = 256;
ctsk.task = SemSampleTaskB;
TaskID_B = tk_cre_tsk(&ctsk);
if(TaskID_B < E_OK)
{
ercd = TaskID_B;
return ercd;
} ctsk.itskpri = 28;
ctsk.stksz = 256;
ctsk.task = SemSampleTaskC;
TaskID_C = tk_cre_tsk(&ctsk);
if(TaskID_C < E_OK)
{
ercd = TaskID_C;
return ercd;
} //创建一个信号量
csem.exinf = NULL;
csem.isemcnt = 4;
csem.maxsem = 4;
csem.sematr = TA_TFIFO | TA_FIRST;
semid = tk_cre_sem(&csem);
if(semid < E_OK)
{
ercd = semid;
return ercd;
}
SemSamplePutCnt(); //启动任务B
tk_sta_tsk(TaskID_B,5); return TRUE;
} void SemSampleTaskA(W stacd,VP exinf)
{
ER ercd = E_OK;
T_RSEM rsem;
rsem = rsem;
while(1)
{
tm_putstring((UB*)"任务A开始申请3个信号量\n");
SemSamplePutCnt();
ercd = tk_wai_sem(semid,3,500); SemSamplePutCnt();
if(ercd == E_OK)
{
LEDTog(LED1);
LEDTog(LED2);
LEDTog(LED3);
} tm_putstring((UB*)"任务A开始释放3个信号量\n");
tk_sig_sem(semid,3);
SemSamplePutCnt(); tk_slp_tsk(500);
} } void SemSampleTaskB(W stacd,VP exinf)
{
ER ercd = E_OK;
T_RSEM rsem; ercd = tk_sta_tsk(TaskID_C,0); SemSamplePutCnt();
tk_wai_sem(semid,4,-1);
ercd = tk_sta_tsk(TaskID_A,0);
if(E_OK == ercd)
{
tm_putstring((UB*)"Start TaskA sucessfuly.\n");
}
else
{
tm_putstring((UB*)"TaskB Failed start Task A.\n");
}
tk_sig_sem(semid,4);
//任务循环
while(1)
{
//任务B需要4个信号量 SemSamplePutCnt();
tm_putstring((UB*)"任务B开始申请4个信号量\n"); if(tk_wai_sem(semid,4,-1) == E_OK)
{
tm_putstring((UB*)"任务B成功获得4个信号量\n");
SemSamplePutCnt();
LEDTog(LED1);
LEDTog(LED2);
LEDTog(LED3);
LEDTog(LED4);
if(tk_sig_sem(semid,4) == E_OK)
{
tm_putstring((UB*)"任务B成功释放4个信号量\n");
}
else
{
tm_putstring((UB*)"任务B释放信号量失败\n");
}
}
else
{
tm_putstring((UB*)"任务B获取信号量失败\n");
}
tk_slp_tsk(200);
} } //防止任务全部休眠导致OS退出的空闲任务
void SemSampleTaskC(W stacd,VP exinf)
{
B b;
while(1)
{
tm_putstring((UB*)"this is in Task C\n");
for(b = 0;b<200;b++);
}
} void SemSamplePutCnt(void)
{
B semcnt[10];
T_RSEM rsem; tm_putstring((UB*)"当前的可用信号量数为: ");
tk_ref_sem(semid, &rsem);
ltostr(rsem.semcnt,semcnt,10,10);
tm_putstring((UB*)semcnt);
tm_putstring((UB*)"\n");
}

实验时串口输出信息:

----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

当前的可用信号量数为: 4
当前的可用信号量数为: 4
任务A开始申请3个信号量
当前的可用信号量数为: 0
Start TaskA sucessfuly.
当前的可用信号量数为: 1
任务A开始释放3个信号量
当前的可用信号量数为: 4
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0
任务B成功释放4个信号量
this is in Task C
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0
任务B成功释放4个信号量
当前的可用信号量数为: 4
任务B开始申请4个信号量
任务B成功获得4个信号量
当前的可用信号量数为: 0

【uTenux实验】信号量的更多相关文章

  1. 【uTenux实验】事件标志

    事件标志是一个用来实现同步的对象,由多个位组成,用作指示对应事件存在的标志.事件标志由用来指示对应事件存在的位模式(bitpattern)和一个等待事件标志的任务队列组成. uTenux提供了一组AP ...

  2. 【uTenux实验】写在开始实验之前

    1.使用的uTenux内核代码:http://www.uloong.cc/cn/download/uTenux_V1.6.00r180.zip 2.uTenux的特性: 1.微内核  2.开放源码.完 ...

  3. 【uTenux实验】任务管理

    任务就是一个无限循环.uTenux提供的任务管理功能是很强大的,包括建立和删除一个任务,启动或退出任务,取消一个任务的启动请求,改变任务的优先级和査询任务状态,使任务进人睡眠状态和唤醒状态,取消唤醒请 ...

  4. 【uTenux实验】邮箱

    邮箱是一个通过在系统(共享)内存空间传递消息来实现同步和通信的对象.uTenux中每个邮箱都包含一个用来发送消息的消息队列和一个用于等待接收消息的任务队列,其使用邮箱功能的消息内容放置在发送方和接收方 ...

  5. 【uTenux实验】互斥体

    互斥体,维基百科中交互斥锁.其定义是这样的:互斥锁(英语:英语:Mutual exclusion,缩写 Mutex)是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制 ...

  6. 【uTenux实验】消息缓冲区

    uTenux的消息缓冲区是一个通过传递大小可变的消息来实现同步和通信的对象. 消息缓冲区由三部分组成:1.待发消息队列  2.等接收消息的任务队列  3.用来保存缓冲消息的空间. 和信号相比,消息队列 ...

  7. 【uTenux实验】集合点端口

    这个是头一次接触的概念.比较不好理解.内核规范中的说明就要20页! 看了王总写的uTenux内核规范之后,有那么一点明白了但理解不深. 集合点端口就像每次工作前的收集情况会.首长下达收集情况指令,各个 ...

  8. 【uTenux实验】内存池管理(固定内存池和可变内存池)

    1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...

  9. 【uTenux实验】时间管理(系统时间/周期性处理/警报处理)

    1.系统时间管理 系统时间管理函数用来对系统时间进行操作,是OS的一个基础性的东西.个人认为,设置系统时间和获取系统时间对OS来说基本是可有可无的. uTenux提供了三个系统时间相关API.分别用于 ...

随机推荐

  1. 2016.9.18 --- Shenyang ol

    1001 Resident Evil 1002 List wants to travel 1003 hannnnah_j’s Biological Test 1004 Mathematician QS ...

  2. java发送 get请求

    package com.java.base; import java.io.BufferedReader; import java.io.InputStreamReader; import java. ...

  3. iOS开发拓展篇—音频处理(音乐播放器2)

    iOS开发拓展篇—音频处理(音乐播放器2) 说明:该文主要介绍音乐播放界面的搭建. 一.跳转 1.跳转到音乐播放界面的方法选择 (1)使用模态跳转(又分为手动的和自动的) (2)使用xib并设置跳转 ...

  4. pwnable.kr-fd

    题目: 链接登录: ssh fd@pwnable.kr -p2222 查看文件及权限: ls –al 看到flag文件,但是当前用户fd并没有读权限. cat fd.c 分析程序: int argc ...

  5. erlang中的lists:foldl()的用法,格式转换实例应用

    lists:foldl(fun(),参数1,参数2):这个函数就是先把参数1传给fun()处理,然后将参数2(列表)中每一个元素,依次传给fun()函数进行处理. lists:foldl(fun(El ...

  6. 使用squid配置透明代理并对上网行为进行控制

    使用Squid配置透明代理 环境:CentOS 6.4 + squid-3.1.10-20.el6_5.3.x86_64 1.检查squid是否默认安装,没有安装先安装 rpm -qa squid 假 ...

  7. GoldenGate 12.2 支持不可见列invisible column的复制

    Oracle Goldengate 12.2现在可以复制不可见列,在以前的版本中是没有此项功能的.示例:在源和目标都创建一个不可见和虚拟列commission SQL>  create tabl ...

  8. Java xml object 互转

    public class ClassRoom { private int id; private String name; private int grade; public int getId() ...

  9. JavaScript基础--简单功能的计算器(十一)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. HDU2222

    http://acm.hdu.edu.cn/showproblem.php?pid=2222 注意: 1. keyword可以相同,因此计算时要累计:cur->num++. 2. 同一个keyw ...