目录
信号量(Semaphore)的功能有一点与互斥量类似,同样是保护临界资源的一种有用方法。信号量可以但不一定实现互斥(不是说不能,一种情况是不存在共享临界区,谈不上互斥,另一种情况是允许共同进入临界区,比如读操作)。
它的运行机制可以理解为:信号量是一个正值,代表资源的可访问数目,当有任务访问时,这个数目减一,任务访问完成时,任务访问结束,释放他,让他加一,信号量为0时,其他任务则不能获取他,选择退出或者等待挂起,直到有信号量释放后,按照优先级来获取信号量,获取后就绪。
把资源想象成车位,信号量就是车位管理员,汽车需要停进有限的车位,当车位管理员发现车位足够时,则将汽车放行,如果车位数为0,则汽车都需要按照某种规则(比如按照优先级)等待空闲车位的出现。
1. 创建
同样,信号量的创建也分动态和静态两种方式,这里只考虑动态方式。
#define rtosSemCreate( \
handle \
name, \
value, \
flag \
) \
{ \
handle = rt_sem_create(name, value, flag); \
}
参数:
handle - 信号量的句柄,属于返回值,创建成功则为非NULL值。
#define rtosSem_t rt_sem_t
name - 信号量的名字,输入参数,字符串。
value - 信号量的默认值,一般是初始化为0
flag - 信号量的标志,支持2种方式:FIFO和PRIO。FIFO模式表示在多个线程等待信号量时,将按照先来先得的顺序获得信号量;PRIO模式表示在多个线程等待信号量时,将由优先级高的线程优先获得信号量。
2. 删除
系统不再使用信号量时,可通过删除信号量以释放系统资源。
#define rtosSemDelete( \
handle \
) \
{ \
rt_sem_delete(handle); \
}
3. 获取
线程通过调用该函数获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量, 并且相应的信号量值会减 1;如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据 time 参数的情况选择直接返回、或挂起等待一段时间、或永久等待,直到其他线程或中断释放该信号量。
#define rtosSemTake( \
handle, \
time, \
ret \
) \
{ \
ret = rt_sem_take(handle, time); \
}
返回0表示获取成功。
4. 释放
释放一个信号量,当信号量的值等于零时,并且有线程等待这个信号量时, 释放信号量将唤醒等待在该信号量线程队列中的第一个线程,由它获取信号量;否则 将把信号量的值加一
#define rtosSemRelease( \
handle, \
ret \
) \
{ \
ret = rt_sem_release(handle); \
}
返回0表示释放成功。
5. 实例
和互斥量的实例类似,2个进程,一个进程负责修改变量,变量值变为10的倍数则释放信号量,这里连续释放2次信号量,另外一个负责显示变量的值,只有获取到信号量才打印变量值。2个进程的优先级依然是显示的优先级更高。
static rtosSem_t sem = NULL;
static uint8_t gSemValue = 0;
static void threadSemShow(void *parameter)
{
while(1)
{
uint32_t ret;
rtosSemTake(sem, RTOS_WAIT_FOREVER, ret);
if(ret == RTOS_EOK)
{
Printf("Sem Value = %d\n", gSemValue);
}
else
{
Printf("Take sem fail\n");
return;
}
}
}
static void threadSemChange(void *parameter)
{
while(1)
{
uint32_t ret;
gSemValue++;
rtosThreadSleep(100);
if((gSemValue % 10) == 0)
{
Printf("Change thread release a semaphore.\n");
rtosSemRelease(sem, ret);
rtosSemRelease(sem, ret);
}
}
}
static void semTestInit(void)
{
rtosSemCreate(sem, "sem", 0, RTOS_IPC_FLAG_FIFO);
rtosCreateThread(
handle1,
"Mutex S",
threadSemShow,
(void *)0,
NULL,
256,
RTOS_PRIORITY_MAX - 2,
100);
rtosCreateThread(
handle2,
"Mutex C",
threadSemChange,
(void *)0,
NULL,
256,
RTOS_PRIORITY_MAX - 1,
100);
rtosStartThread(handle1);
rtosStartThread(handle2);
}
打印结果:
Change thread release a semaphore.
Sem Value = 10
Sem Value = 10
Change thread release a semaphore.
Sem Value = 20
Sem Value = 20
Change thread release a semaphore.
Sem Value = 30
Sem Value = 30
Change thread release a semaphore.
Sem Value = 40
Sem Value = 40
Change thread release a semaphore.
Sem Value = 50
Sem Value = 50
因为修改进程会释放2次信号量,所以显示进程会连续2次拿到信号量,从而打印了2次值。