队列
不同生产者A,B往队列里面写数据
不同消费者C,D往队列里面读数据
如果不用队列,A,B在写数据时候,A不能被B打断。那么需要用个标志位做互斥量,B进任务时,查看标志位在使用中,那么主动等待标志位为0时候再使用。
taskfunction()
{
if(flag ==0)
{
flag = 1;
A();
flag = 0;
}
}
这样代码存在问题
1,A任务执行时,轮询到B任务,虽然B任务无法被执行,但B任务占用了CPU使用率。
2,如果A任务运行到flag = 1,被B任务切换。那么B也可以继续往下执行,直到最后执行完成flag = 0,这样A再切回来时,又要从头执行。
因此使用队列替代全局变量flag判断。
队列的使用步骤
1,创建队列
2,初始化写入一次队列
3,任务中读队列,读到继续往下执行,读不到,阻塞在这里。
.
int main( void )
{
#ifdef DEBUG
debug();
#endif
qHandle_f = xQueueCreate(10,sizeof(int));
xQueueSend(qHandle_f, &value, portMAX_DELAY);
xTaskCreate(TaskGenericFunction, "Task4", 100, (void *)4, 1, NULL);
xTaskCreate(TaskGenericFunction, "Task5", 100, (void *)5, 1, NULL);
vTaskStartScheduler();
);
void TaskGenericFunction(void * param)
{
int val = (int )param;
while (1)
{
xQueueReceive(qHandle_f, &value, portMAX_DELAY);
printf("%d", val);
xQueueSend(qHandle_f, &value, portMAX_DELAY);
vTaskDelay(1);
}
}
注意上面两处注意事项
1,创建完成队列后,需要写入一次,否则没有数据的队列,读队列时会发生阻塞
qHandle_f = xQueueCreate(10,sizeof(int));
xQueueSend(qHandle_f, &value, portMAX_DELAY);
2,不同任务调用同一个函数时,在使用队列时,需要加vTaskDelay,给其他任务预留运行时间,否则会一直运行这个任务
队列集
队列集的本质仍然是队列,但其特殊之处在于它内部存放的是“队列句柄”而不是直接的数据项。
当其中有队列有数据到达时,队列集的接口会返回可读的队列句柄。用户获得句柄后,就可以从相应的队列中读取数据。
与普通队列的区别
队列是一种基本的数据结构,它遵循FIFO(先进先出)的原则,即最早进入队列的数据项将首先被取出。队列通常用于任务之间的通信和数据传递,每个任务可以往队列中写入数据,也可以从队列中读取数据。队列有一定的容量限制,当队列满时,试图向其添加更多数据项的操作将被阻塞,直到有空间可用。
队列集实际上是保存了一组队列句柄的队列。它允许任务等待多个队列中的任何一个,当其中任何一个队列有数据到达时,队列集就会唤醒等待的任务。这样,任务就可以更灵活地响应来自不同输入设备的事件和数据。
总结:
功能:实现从不同设备中获取数据,数据长度 = 队列A+B。。
main:
- 创建队列A,B
- 创建队列集
- 将队列添加到队列集
生产者
写入队列
消费者
1)从队列集读出队列
2)处理数据
int main( void )
{
static char str2[20];
//1.创建队列
qHandle_f1 = xQueueCreate(20,sizeof(int));
qHandle_f2 = xQueueCreate(20,sizeof(str2));
//2.创建队列集
xQueueSet = xQueueCreateSet(40);
//3.添加队列至队列集
xQueueAddToSet(qHandle_f1,xQueueSet);
xQueueAddToSet(qHandle_f2,xQueueSet);
prvSetupHardware();
printf("Hello, world!\r\n");
xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
xTaskCreate(Task3Function, "Task3", 100, NULL, 1, NULL);
/* Start the scheduler. */
vTaskStartScheduler();
return 0;
}
void Task1Function(void * param)
{
int i = 0;
while (1)
{
for(i = 0;i < 100;i++)
xQueueSend(qHandle_f1, &i, portMAX_DELAY);
}
}
void Task2Function(void * param)
{
int i;
char *str1 ="the number is:";
char str2[20];
char nchar;
while (1)
{
for(i = 0;i<100;i++)
{
nchar = '0'+i;
strcpy(str2,str1);
strcat(str2,&nchar);
xQueueSend(qHandle_f2, str2, portMAX_DELAY);
}
}
}
void Task2Function(void * param)
{
int i;
char *str1 ="the number is:";
char str2[20];
char nchar;
while (1)
{
for(i = 0;i<100;i++)
{
nchar = '0'+i;
strcpy(str2,str1);
strcat(str2,&nchar);
xQueueSend(qHandle_f2, str2, portMAX_DELAY);
}
}
}
程序中,
在main函数中,创建队列集,创建队列,将队列添加至队列集
其中队列长度都是20,存放数据的size不同,一个是int型,一个是指针类型
队列集的总长度是20+20。
问题:如果这里的数据第一个20个char,第二个是20个指针。队列集总长度是多少?
1,队列的长度20,如果超过20发生阻塞,其他任务可以运行。
2,队列集的长度20+20,实际上是可以比20+20更大,可以存放的数据更多,如果队列集数据过小,比如也为20,那会出现队列集一直存放第一个任务的数据。而第二个得不到存储空间。
正确的做法应该是大于等于20+20
在task1中,产生0~100的数据,并把数据存入20个空间的队列1,当队列满了,会进入阻塞
在task2中,产生0~100的数据,合并字符串后,并把数据存入20个空间的队列2,当队列满了,会进入阻塞
在task3中,从队列集中取出队列,从队列中取出数据打印出来