参考https://blog.youkuaiyun.com/booksyhay/article/details/82743623
在6-1中的生产者方案中:
尽管这种解决方案是正确的,但仍有机会对其性能进行一次小改进。 想象一下,当生产者发出信号时,至少有一个消费者在队列中。 如果调度程序允许消费者运行,接下来会发生什么? 它会立即阻塞生产者(仍然)持有的互斥锁。
阻塞和唤醒是中等昂贵的操作; 不必要地执行它们会损害程序的性能。 所以重新排列生产者可能会更好:
改进后的生产者代码:
int put_events = 0;
while(1)
{
wait_event();
osSemaphoreAcquire(sem_mutex, osWaitForever);
{
event_add(&put_events);
printf("put events: %d\r\n", put_events);
}
osSemaphoreRelease(sem_mutex);
osSemaphoreRelease(sem_items);
osDelay(1500);
}
上面的生产者与消费者,共享缓冲区是无限的,实际情况并非如此,改进上面的方案:
添加第二个信号量以跟踪缓冲区中的可用空间数
具有有限缓冲区的生产者 - 消费者
当消费者移除项目时,它应该发送信号给spaces。 当生产者到达时,它应该递减spaces信号量,此时它可能会阻塞,直到下一个消费者发出信号。
为了避免死锁,生产者和消费者在获取互斥锁之前检查可用性。 为获得最佳性能,他们会在发出信号之前释放互斥锁。
初始化
其中sem_spaces 初始化为5
osSemaphoreId_t sem_mutex;
sem_mutex = osSemaphoreNew(1, 1, NULL);
osSemaphoreId_t sem_mutex;
sem_items = osSemaphoreNew(1, 0, NULL);
osSemaphoreId_t sem_spaces;
sem_spaces = osSemaphoreNew(5, 5, NULL);
生产者
int put_events = 0;
while(1)
{
wait_event();
printf("available sems: %d\r\n", osSemaphoreGetCount(sem_spaces));
osSemaphoreAcquire(sem_spaces, osWaitForever);
osSemaphoreAcquire(sem_mutex, osWaitForever);
{
event_add(&put_events);
printf("put events: %d\r\n", put_events);
}
osSemaphoreRelease(sem_mutex);
osSemaphoreRelease(sem_items);
osDelay(500);
}
消费者
int get_events = 0;
while(1)
{
osSemaphoreAcquire(sem_items, osWaitForever);
osSemaphoreAcquire(sem_mutex, osWaitForever);
{
event_get(&get_events);
}
osSemaphoreRelease(sem_mutex);
osSemaphoreRelease(sem_spaces);
event_process(get_events);
osDelay(2000);
}
其中特意将消费的速率明显大于生产的速率!
结论:
可以看到sem_spaces信号量有效数减为0后,生产者置事件需要消费者释放sem_spaces,才能放入事件。而且可以看到消费者获取的事件值是生产者生产的上一个事件值。