Synchronization and data transfer between tasks and the interrupt handler

Need help understanding how to optimally organize synchronization and data transfer between tasks and the interrupt handler.
I use RTOS in Stm32
There are three tasks, the third task handles transmission and reception via UART.
To receive I use the DMA interrupt handler, when all the data receive in the global variable, I give a semaphore in the interrupt and then task three wakes up, does something and goes into blocking.
The first two tasks are doing something and when they have data, they transmit information to task three through queues.
The problem is that queues and semaphore do not work in the same task, I found out that there are queues sets, but I am not sure that such a solution is optimally correct.
use queues from interrupt only to inform the task that there is data, process it, this is probably not the right solution…
I need to receive data from the interrupt handler and somehow inform task three so that it understands that the data receive from the interrupt handler.
And i need to accept data from the first two tasks so that task three understands that this data receive from task one or two for transmit to UART

Each task should have A thing it is waiting for (Which can be a QueueSet, but I try to avoid that). If you can’t define that, then likely your task division isn’t good.

Note, since Semaphores are based on Queue, I think you can put them in a QueueSet, but double check that.

The other option would be don’t make task3 take instructions by both queues and semaphores, but have another task waiting on the semaphore, and inform task3 via the queue.

You don’t recommend using QueueSet, but why?)

I avoid QueueSets because I tend not to find the need for a task to be taking data from multiple queues. If multiple tasks send data to a task, they will all use the same queue and the same formatted data (or a structure which indicates which sub-type of data it is)

If the task is taking different sorts of data, maybe it should have been multiple tasks, one for each type of data.

Note, I am not saying you can’t use QueueSets, I just find them that useful for the way I design programs.

In the documentation, the API also advises that if there is no particular need to use QueueSets, then it is better to use classic queues, and I thought maybe this does not work stably…
Thanks for explaining.

The question is if your task needs to simultaneously wait for data from any of a multitude of Queues, then you want to use a QueueSet. The point is that it ties the receiving end of the Queue together and reads from them must be done via the QueueSet protocol (Get the Queue ID from the QueueSet, then read that Queue) or you can break things. z

IF you need to do it that way, it works, but if you don’t actually need to wait for data from an arbitrary one of the queue, it adds complications. Since multiple tasks can write to a single Queue, doing it that way is often much simpler.