信号量(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. Exit函数

    1函数: exit() 函数名: exit() 所在头文件:stdlib.h 功 能: 关闭所有文件,终止正在执行的进程. exit(1)表示异常退出.这个1是返回给操作系统的. exit(x)(x不 ...

  2. SSH(2)

    1.用户登录 index页面跳转到登录页面 <% String path = request.getContextPath(); String basePath = request.getSch ...

  3. Android 4.2以上的手机USB调试设置

    今天遇到一个问题,我手上有两部手机一部是红米.一部是中兴的青漾QY N986,两部手机的Android系统都是4.2.1的,连接到电脑测试,找了半天没有找到设置开发者选项,后来在网上找了半天,才发现g ...

  4. Android SurfaceView

    今天介绍一下SurfaceView的用法,SurfaceView一般与SurfaceHolder结合使用,SurfaceHolder用于向与之关联的SurfaceView上绘图,调用SurfaceVi ...

  5. eclipse快捷键用不了

    ctrl+shift+R是eclipse最常用的快捷键之一,用于打开资源,输入文件名或文件名中的前几个字母,就可以打开工作区中任意文件 今天在打开eclipse,使用该快捷键时,提示“该快捷方式所指向 ...

  6. hibernate 的 CascadeType 属性

    hibernateintegerstringfloatclassmerge @Entity @Table(name="orders")public class Order { // ...

  7. dij单源最短路纯模板

    #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> ...

  8. magento jQuery冲突N种方法

    在做修改模板的时候在page中加入jquery库发现原本自带的js冲突 商品无法加入购物车,很多js都没有效果 这是jQuery和magento自带prototype的冲突解决版本有很多种,说个简单点 ...

  9. 关于 edittext 软键盘退出监听解决办法

    edittext 有个onCreateInputConnection 的方法,通过它可以自定义一个输入法连接器,那里连接器里面有个方法(finishComposingText)能监听输入完成的动作. ...

  10. 根据滑动显隐状态栏的iOS实现

    之前很多兄弟问如何实现类似于淘宝客户端搜索列表那种动态显隐的效果,这几天刚好有时间,就实现了几个例子搞一下,其实原理很简单,也参考了github上一位兄弟的实现.不多说,上代码 @interface ...