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.

Document

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.