1.除了队列和信号量,FreeRTOS使用哪些其他机制来实现任务间通信?
使用互斥锁,互斥锁是一种用于保护共享资源的机制。当一个任务需要使用一个共享资源时,它必须首先获取互斥锁。如果互斥锁已经被另一个任务获取,那么这个任务就需要等待,直到互斥锁被释放。在FreeRTOS中,可以使用xSemaphoreCreateMutex()函数来创建一个互斥锁。
使用事件标志组,事件标志组是一种用于表示一组事件发生状态的数据结构。每一个事件都有一个对应的标志,当事件发生时,标志被设置,当事件被处理时,标志被清除。在FreeRTOS中,可以使用xEventGroupCreate()函数来创建一个事件标志组。
2.直接任务通知是什么,如何使用它们?
任务通知是RTOS中常用的用于任务间交互的功能。发送通知的函数需要设置为1
3.总结二进制信号量和计数型信号量的区别,以及他们的使用场景。
(1)二进制信号量:最快和常用的信号量,提供阻塞方式,用于实现同步或互斥。计数信号量:类似于二进制信号量,记录信号量被释放的次数。适合于一个资源的个实例需要保护的情况。
(2)二进制信号量可以用来进行同步和互斥,没有优先级反转保护,不支持优先级继承协议和嵌套;而且对于二进制信号量,不同的任务都可以对其进行释放,在中断任务中也可以释放二进制信号量,甚至当任务持有二进制信号量时,其它任务都可以删除它。
(3)计数器信号量使用一个计数器,允许多次获取和释放信号量,用于操作系统中共享资源的多个任务的使用,是实现同步与互斥的另一种手段,适用于保护多份复制的资源。与二进制信号量相同的是,如果信号量被释放时存在被阻塞的任务,那么被阻塞的任务将被解除阻塞。与二进制信号量不同的是,它还跟踪信号量被释放的次数,每释放一个信号量,计数器加一,每提取一个信号量,计数器减一。如果信号量被释放时不存在阻塞的任务,那么计数器将加一,这意味着一个被释放两次的信号量可以无阻塞地被提取两次。
4.总结FreeRTOS中同步和互斥的五种方法的使用方法
队列可以用于"任务到任务"、“任务到中断”、"中断到任务"直接传输信息。
信号量只需要维护一个数值,使用信号量效率更高、更节省内存
互斥量用于临界资源的保护一般建议使用互斥量。
事件组一个 32 位的事件集合,其中的每一位都可以表示一个事件.每一位事件的含义由程序员决定,比如:Bit0 表示用来串口是否就绪,Bit1 表示按键是否被按下
任务通知在 FreeRTOS 中,每一个任务都有两个用于任务通知功能的数组,分别为 " 任务通知数组 " 和 " 任务通知状态数组 " 。
5.总结任务通知和其他任务通信机制的区别
任务通知与其他通信方式的区别 使用队列、信号量、事件组时,我们都要事先创建对应的结构体,双方通过中间的结构体通信: 但我们的任务通知只需要对方的TCB结构体即可任务结构体 TCB 中就包含了内部对象,可以直接接收别人发过来的"通知"
6.生产者和消费者模型
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
sem_t empty;
sem_t full;
pthread_mutex_t mutex; // 互斥锁
void *producer(void *arg) {
int item = 1;
while (1) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
// 生产
buffer[in] = item;
printf("Producer produced item %d\n", item);
in = (in + 1) % BUFFER_SIZE;
item++;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
void *consumer(void *arg) {
while (1) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
// 消费
int item = buffer[out];
printf("Consumer consumed item %d\n", item);
out = (out + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
}
int main() {
pthread_t producer_thread, consumer_thread;
// 初始化
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
// 创建生产者和消费者线程
pthread_create(&producer_thread, NULL, producer, NULL);
pthread_create(&consumer_thread, NULL, consumer, NULL);
pthread_join(producer_thread, NULL);
pthread_join(consumer_thread, NULL);
// 销毁
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
}