In this example, we going to synchronize tasks to write and read the data stored in a queue. To synchronize the processes we are going to use a semaphore counter, to manage 4 task, 2 of them to write and the rest to read the data in Queue, the semaphore help us to synchronize and prevent Rise conditions with the queue, while 2 task are writing the other task to read cannot access to the data of the queue.
Code Example:
#include "bsp.h"
static void TaskWrite1( void *parameter );
static void TaskWrite2( void *parameter );
static void TaskRead1( void *parameter );
static void TaskRead2( void *parameter );
QueueHandle_t Queue;
SemaphoreHandle_t Semph;
int main( void )
{
HAL_Init( );
/*enable RTT and system view*/
SEGGER_SYSVIEW_Conf( );
SEGGER_SYSVIEW_Start( );
Queue = xQueueCreate( 2, sizeof(uint8_t)); /* Queue Creation */
Semph = xSemaphoreCreateCounting(2,0); /* Counter Semaphore creation */
xTaskCreate( TaskWrite1, "Task_W1", 128u, NULL, 4u, NULL ); /* Register Task1 to write in Queue */
xTaskCreate( TaskWrite2, "Task_W2", 128u, NULL, 3u, NULL ); /* Register Task2 to write in Queue */
xTaskCreate( TaskRead1, "Task_R1", 128u, NULL, 2u, NULL ); /* Register Task1 to read the Queue */
xTaskCreate( TaskRead2, "Task_R2", 128u, NULL, 1u, NULL ); /* Register Task2 to read the Queue */
vTaskStartScheduler( ); /* Initialize the Kernel */
return 0u;
}
static void TaskWrite1( void *parameter )
{
uint8_t DataSend = 0; /* Register Variable to count */
for(;;)
{
xSemaphoreTake(Semph,0); /* increment semaphore count */
xQueueSend( Queue, &DataSend, 0 ); /* Send the value of current count */
DataSend++; /* Increment cunt of variable */
vTaskDelay(100); /* Task delay */
}
}
static void TaskWrite2( void *parameter )
{
uint8_t DataSend = 255; /* Variable to store a value */
for(;;)
{
xSemaphoreTake(Semph,0); /* Increment semaphore count */
xQueueSend( Queue, &DataSend, 0 ); /* Send the value set */
vTaskDelay( 100 ); /* Task delay */
}
}
static void TaskRead1( void *parameter )
{
uint8_t ReceivedData; /* Variable to store data read from Queue */
for(;;)
{
if (uxSemaphoreGetCount(Semph) <= 1) /* Get the current semaphore count */
{
xSemaphoreGive(Semph); /* Decrement semaphore count */
xQueueReceive( Queue, &ReceivedData, 0 ); /* Read data from Queue */
SEGGER_SYSVIEW_PrintfHost( "Received Data from TaskRead1: %d", ReceivedData ); /* Print the data received */
}
else
{
taskYIELD(); /* Give time processor to other task */
}
vTaskDelay(50); /* task delay */
}
}
static void TaskRead2( void *parameter )
{
uint8_t ReceivedData; /* Variable to store data read from Queue */
for(;;)
{
if(uxSemaphoreGetCount(Semph) <= 1) /* Get the current semaphore count */
{
xSemaphoreGive(Semph); /* Decrement semaphore count */
xQueueReceive( Queue, &ReceivedData, 0 ); /* Read data from Queue */
SEGGER_SYSVIEW_PrintfHost( "Received Data from TaskRead2: %d", ReceivedData ); /* Print the data received */
}
else
{
taskYIELD(); /* Give time processor to other task */
}
vTaskDelay(50); /* task delay */
}
}
SystemView Output:
Terminal shows how the task receives synchronously the correct message, Task_R1 always receives the counter and Task_R2 receives a static value.
Timeline:
Observe the execution of the task, task_w1 executes first sending the static message, and task_w2 sends the increment number. Tasks are using a semaphore to synchronize the execution of the reader task, each reader task will receive the appropriate task to be printed on the terminal.