1 SYS/BIOS简介
SYS/BIOS是一种用于TI的DSP平台的嵌入式操作系统(RTOS)。
2 任务
2.1 任务调度
SYS/BIOS任务线程有0-31个优先级(默认0-15,优先级0被空闲线程使用,任务最低优先级为1,最高优先级为15),在内存允许的情况下可以不限制的创建任务数量。SYS/BIOS有独立的内存堆栈,可以为等待某一事件的发生而被挂起,任务会被其他更高优先级的线程打断。
2.2 动态创建任务
以下例程将动态创造两个任务:
cpp
/*
* ======== task ========
*/
Void taskFxn1(UArg a0, UArg a1) {
System_printf("enter task1\n");
Task_sleep(10);
System_printf("exit task1\n");
System_flush();
}
Void taskFxn2(UArg a0, UArg a1) {
System_printf("enter task2\n");
Task_sleep(10);
System_printf("exit task2\n");
System_flush();
}
/*
* ======== main ========
*/
Int main() {
Task_Handle task1;
Task_Handle task2;
Task_Params taskParams;
// 创建两个任务
Task_Params_init(&taskParams);
taskParams.priority = 1;//任务优先级
taskParams.stackSize = 1024;//任务栈大小
task1 = Task_create(taskFxn1, &taskParams, NULL);
Task_Params_init(&taskParams);
taskParams.priority = 2;//任务优先级
taskParams.stackSize = 1024;//任务栈大小
task2 = Task_create(taskFxn2, &taskParams, NULL);
BIOS_start(); /* does not return */
return (0);
}
3 同步模块
3.1 信号量
3.1.1 信号量简介
信号量通常用于协调一些处于竞争关系的任务之间对共享资源的访问。可以使任务处于挂起状态,用来等待某一个特定的事件,只有当这个事件发布的时候才能继续执行任务。
信号量的操作主要包括Semaphore_pend()
和Semaphore_post()
两个API。Semaphore_pend()
用于请求信号量,如果信号量的计数值大于0,则任务可以继续执行,否则任务将被挂起等待信号量的发布。Semaphore_post()
用于释放信号量,增加信号量的计数值,如果其他任务因等待此信号量而被挂起,则会唤醒这些任务中的一个。
简单来说:信号量的值为0的时候任务处于挂起状态,信号量大于等于1的时候任务恢复继续执行。
信号量有两种模式:计数信号量(Counting)和二进制信号量(Binary)。计数信号量可以有大于1的计数值,表示多个资源或资源的多个访问权限;而二进制信号量只有0和1两个状态,用于最简单的同步机制,比如一个资源的锁定和解锁。下面是两种计数模式的区别:
3.1.2 动态创建信号量
以下是创建信号量的例程,其中任务2优先级高于任务1,所以进入系统之后优先运行任务2,任务2执行到Semaphore_pend(sem, BIOS_WAIT_FOREVER);时,代表信号量为0将任务2挂起,运行任务1。任务1开始后,运行到Semaphore_post(sem);代表信号量为1,之前被挂起的任务2恢复运行。
cpp
Semaphore_Handle sem;
/*
* ======== task ========
*/
Void taskFxn1(UArg a0, UArg a1) {
while (1) {
System_printf("进入任务1\n");
System_flush();
// 发布
Semaphore_post(sem);
System_printf("退出任务1\n");
System_flush();
}
}
Void taskFxn2(UArg a0, UArg a1) {
while (1) {
System_printf("进入任务2\n");
System_flush();
// 挂起
Semaphore_pend(sem, BIOS_WAIT_FOREVER);
System_printf("退出任务2\n");
System_flush();
}
}
/*
* ======== main ========
*/
Int main() {
Task_Handle task1;
Task_Handle task2;
Error_Block eb;
System_printf("enter main()\n");
Error_init(&eb);
// 创建两个任务
Task_Params taskParams;
Task_Params_init(&taskParams);
taskParams.priority = 1;
taskParams.stackSize = 1024;
task1 = Task_create(taskFxn1, &taskParams, NULL);
Task_Params_init(&taskParams);
taskParams.priority = 2;
taskParams.stackSize = 1024;
task2 = Task_create(taskFxn2, &taskParams, NULL);
// 创建一个信号量
Semaphore_Params semParams;
Semaphore_Params_init(&semParams);
semParams.mode = Semaphore_Mode_BINARY; //二进制模式
sem = Semaphore_create(0, &semParams, NULL); //1为该信号量的初始值
BIOS_start(); /* does not return */
return (0);
}
运行结果:
3.2 邮箱
3.2.1 邮箱简介
邮箱SYS/BIOS系统用来在任务间进行buffer传输的。可以将邮箱理解为一个FIFO的队列,Mailbox_post表示向队列写数据,Mailbox_pend表示向队列读数据,如果队列数据存满了,那么就无法向队列再写新的数据。
如果队列已满,执行 Mailbox_post则返回0,在time_out为BIOS_WAIT_FOREVER情况下,则任务被挂起,直到队列可以写数据。
如果队列为空,执行Mailbox_pend则返回0,在time_out为BIOS_WAIT_FOREVER情况下,则任务被挂起,直到队列有数据。
3.2.2 动态创建邮箱
cpp
Mailbox_Handle mbx;
Void task_writer(UArg arg0, UArg arg1) {
Int32 data_addr;
data_addr = 12345678;
//推送消息到邮箱
//第一个参数为邮箱句柄,第二个参数为传递的消息地址,第三个表示超时时间
Mailbox_post(mbx, &data_addr, BIOS_NO_WAIT);
System_printf("writer done\n");
System_flush();
}
Void task_reader(UArg arg0, UArg arg1) {
Int32 read_addr;
while (1) {
//第一个参数为邮箱句柄,第二个参数为传递的消息地址,第三个表示超时时间
Mailbox_pend(mbx, &read_addr, BIOS_WAIT_FOREVER);
System_printf("read data = %d \n", read_addr);
System_flush();
}
}
Int main() {
Task_Params taskParams;
Mailbox_Params mbxParams;
//创造一个邮箱实例
Mailbox_Params_init(&mbxParams);
//在Mailbox_create中,第一个参数表示邮箱传递消息的字节数,第二个参数表示邮箱消息的最大数量
mbx = Mailbox_create(sizeof(Int32), 1, &mbxParams, NULL);
//创建一个任务实例
Task_Params_init(&taskParams);
//写任务
taskParams.priority = 10;
Task_create(task_writer, &taskParams, NULL);
//读任务
taskParams.priority = 1;
Task_create(task_reader, &taskParams, NULL);
BIOS_start();
return (0);
}
运行结果: