VxWorks 7 信号量概述 #
在实时操作系统(RTOS)中,信号量是一种重要的同步机制,用于管理多任务环境下的资源访问和任务同步。VxWorks 7提供了多种类型的信号量来满足不同的应用场景需求,主要包括:
- 互斥信号量(Mutex Semaphores):确保对共享资源的互斥访问。
- 二进制信号量(Binary Semaphores):类似于互斥信号量,但更简单,常用于任务同步。
- 计数信号量(Counting Semaphores):可以计数,可以表示多个资源的可用性。
信号量的基本操作 #
- 创建信号量:
- semMCreate 创建互斥信号量。
- semBCreate 创建二进制信号量。
- semCCreate 创建计数信号量。
- 获取信号量:
- semTake 阻塞模式下获取信号量。
- semTakeWithTimeout 带有超时功能的获取信号量。
- 释放信号量:
- semGive 释放信号量。
- 删除信号量:
- semDelete 删除信号量。
代码示例 #
创建并使用互斥信号量 #
#include <vxWorks.h>
#include <semLib.h>
#include <taskLib.h>
#include <stdio.h>
/* 互斥信号量的句柄 */
SEM_ID mutexSem;
void task1(void)
{
while (1)
{
/* 获取互斥信号量 */
if (semTake(mutexSem, WAIT_FOREVER) == OK)
{
printf("Task1: Got the mutex\n");
/* 临界区的代码 */
/* 例如,修改共享资源 */
/* 释放互斥信号量 */
semGive(mutexSem);
taskDelay(100); // 延时以模拟任务执行
}
}
}
void task2(void)
{
while (1)
{
/* 获取互斥信号量 */
if (semTake(mutexSem, WAIT_FOREVER) == OK)
{
printf("Task2: Got the mutex\n");
/* 临界区的代码 */
/* 例如,访问共享资源 */
/* 释放互斥信号量 */
semGive(mutexSem);
taskDelay(100); // 延时以模拟任务执行
}
}
}
int main()
{
/* 创建互斥信号量 */
mutexSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
if (mutexSem == NULL)
{
printf("Failed to create mutex semaphore\n");
return ERROR;
}
/* 创建任务 */
if (taskSpawn("t1", 100, 0, 4000, (FUNCPTR)task1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
{
printf("Failed to spawn task1\n");
return ERROR;
}
if (taskSpawn("t2", 100, 0, 4000, (FUNCPTR)task2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
{
printf("Failed to spawn task2\n");
return ERROR;
}
return 0;
}
错误处理 #
为了严谨,上述代码需要添加相关的错误处理,如下:
#include <vxWorks.h>
#include <semLib.h>
#include <taskLib.h>
#include <stdio.h>
#include <errnoLib.h>
/* 互斥信号量的句柄 */
SEM_ID mutexSem;
void task1(void)
{
STATUS status;
while (1)
{
/* 获取互斥信号量 */
status = semTake(mutexSem, WAIT_FOREVER);
if (status != OK)
{
printf("Task1: Failed to take semaphore. Error: %s\n", strerror(errnoGet()));
}
else
{
printf("Task1: Got the mutex\n");
/* 临界区的代码 */
/* 例如,修改共享资源 */
/* 释放互斥信号量 */
status = semGive(mutexSem);
if (status != OK)
{
printf("Task1: Failed to give semaphore. Error: %s\n", strerror(errnoGet()));
}
taskDelay(100); // 延时以模拟任务执行
}
}
}
void task2(void)
{
STATUS status;
while (1)
{
/* 获取互斥信号量 */
status = semTake(mutexSem, WAIT_FOREVER);
if (status != OK)
{
printf("Task2: Failed to take semaphore. Error: %s\n", strerror(errnoGet()));
}
else
{
printf("Task2: Got the mutex\n");
/* 临界区的代码 */
/* 例如,访问共享资源 */
/* 释放互斥信号量 */
status = semGive(mutexSem);
if (status != OK)
{
printf("Task2: Failed to give semaphore. Error: %s\n", strerror(errnoGet()));
}
taskDelay(100); // 延时以模拟任务执行
}
}
}
int main()
{
STATUS status;
/* 创建互斥信号量 */
mutexSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
if (mutexSem == NULL)
{
printf("Failed to create mutex semaphore. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
/* 创建任务 */
status = taskSpawn("t1", 100, 0, 4000, (FUNCPTR)task1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (status == ERROR)
{
printf("Failed to spawn task1. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
status = taskSpawn("t2", 100, 0, 4000, (FUNCPTR)task2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (status == ERROR)
{
printf("Failed to spawn task2. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
return 0;
}
错误处理的说明:
- semTake 和 semGive 函数的返回值被检查,如果返回值不是 OK,则表示操作失败,此时会打印错误信息。
- 使用 errnoGet() 函数获取错误码,并通过 strerror() 将错误码转换为可读的错误信息。
- 对于信号量的创建和任务的生成,同样检查返回值,保证操作成功,不成功时提供相应的错误信息。
- 这样做可以帮助你更容易地诊断和修复程序中的问题,尤其是在信号量操作或任务管理方面。
超时处理 #
#include <vxWorks.h>
#include <semLib.h>
#include <taskLib.h>
#include <stdio.h>
#include <errnoLib.h>
/* 互斥信号量的句柄 */
SEM_ID mutexSem;
/* 超时时间定义,单位为ticks */
#define SEM_TIMEOUT 100
void task1(void)
{
STATUS status;
while (1)
{
/* 获取互斥信号量,带超时处理 */
status = semTake(mutexSem, SEM_TIMEOUT);
if (status != OK)
{
if (status == ERROR)
{
printf("Task1: Failed to take semaphore. Error: %s\n", strerror(errnoGet()));
}
else if (status == S_objLib_OBJ_TIMEOUT)
{
printf("Task1: Timed out waiting for semaphore.\n");
}
}
else
{
printf("Task1: Got the mutex\n");
/* 临界区的代码 */
/* 例如,修改共享资源 */
/* 释放互斥信号量 */
status = semGive(mutexSem);
if (status != OK)
{
printf("Task1: Failed to give semaphore. Error: %s\n", strerror(errnoGet()));
}
taskDelay(100); // 延时以模拟任务执行
}
}
}
void task2(void)
{
STATUS status;
while (1)
{
/* 获取互斥信号量,带超时处理 */
status = semTake(mutexSem, SEM_TIMEOUT);
if (status != OK)
{
if (status == ERROR)
{
printf("Task2: Failed to take semaphore. Error: %s\n", strerror(errnoGet()));
}
else if (status == S_objLib_OBJ_TIMEOUT)
{
printf("Task2: Timed out waiting for semaphore.\n");
}
}
else
{
printf("Task2: Got the mutex\n");
/* 临界区的代码 */
/* 例如,访问共享资源 */
/* 释放互斥信号量 */
status = semGive(mutexSem);
if (status != OK)
{
printf("Task2: Failed to give semaphore. Error: %s\n", strerror(errnoGet()));
}
taskDelay(100); // 延时以模拟任务执行
}
}
}
int main()
{
STATUS status;
/* 创建互斥信号量 */
mutexSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE);
if (mutexSem == NULL)
{
printf("Failed to create mutex semaphore. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
/* 创建任务 */
status = taskSpawn("t1", 100, 0, 4000, (FUNCPTR)task1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (status == ERROR)
{
printf("Failed to spawn task1. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
status = taskSpawn("t2", 100, 0, 4000, (FUNCPTR)task2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
if (status == ERROR)
{
printf("Failed to spawn task2. Error: %s\n", strerror(errnoGet()));
return ERROR;
}
return 0;
}
超时处理的说明:
- 在调用 semTake 时,第二个参数不再是 WAIT_FOREVER,而是使用了 SEM_TIMEOUT 来设置超时时间。
- 如果在指定时间内未获取到信号量,semTake 会返回 S_objLib_OBJ_TIMEOUT,此时可以通知任务超时。
- 这种方式可以防止任务因等待信号量而被无限期阻塞,特别有用在需要实时响应的系统中。
注意事项 #
- 信号量必须在使用前创建,并且在不再需要时删除以释放资源。
- 长时间持有信号量可能会导致优先级反转问题,VxWorks提供了优先级继承来解决这个问题。
- 使用信号量时要考虑任务的优先级和实时性要求,以避免死锁等问题。
这个示例展示了如何在VxWorks 7中使用互斥信号量来协调两个任务对共享资源的访问。实际应用中,你可能需要根据具体需求选择不同的信号量类型,并考虑性能与资源利用的平衡。