Counting semaphore doubt

sasikalaswathi wrote on Monday, November 18, 2019:

Created the counting semaphore with the count as 2.

Created the 2 semaphore taking tasks (task1,task2) and one semaphore giving task(task3).
While running the code, semaphore gets only for task1, task2 doesn’t get the chance for the semaphore.

But whenever i changed the value from to 1 in API xSemaphoreCreateCounting(2,0), got the semaphore for two tasks (task1 and task2).

I don’t understood this behaviour. could you explain why ?

Attached the code for reference.

rtel wrote on Monday, November 18, 2019:

I can replicate this using your code and think it is a similar issue to
that explained in the book with giving and taking mutexes in a tight
loop. I can’t explain it fully yet (need to dive deeper) but think when
there is a maximum count of two the semaphore is effectively always
available to any given task that happens to be running, so it doesn’t
block when attempting to obtain the semaphore. On the other hand if the
max count is 1 only one task can have the semaphore at a time, so the
other task that attempts to obtain it will block.

Unlike the case described in the book, I can’t yet explain why only one
task appears to run as they are the same priority, but will look into it
more and report back.

rtel wrote on Monday, November 18, 2019:

Yes, so I think this is the same as described in the book, and is the
logical behaviour when tracing the execution.

The tasks all have the same priority. One task free runs taking the
semaphore. Taking the semaphore can unblock the other task that is
attempting to take the semaphore - but the other task doesn’t run yet as
it has the same priority as the task that is running. The task that is
running continues taking the semaphore until a tick interrupt happens to
run - at which point the task that was unblocked gets a time slice but
by that time the semaphore is empty again so all it does is return to
the blocked state (it does that inside the semaphore take API function).
Therefore it will appear as if only one task ever runs until it just so
happens that a tick interrupt occurs when the semaphore is available -
so the other task just happens to be able to complete its ‘take’ operation.

If you add a taskYIELD() into each function that is taking the semaphore
then you can force a context switch while the semaphore is available,
and therefore allow the other ‘take’ task to obtain it - then they make
the same number of successful takes each.

sasikalaswathi wrote on Tuesday, November 19, 2019:

Hi Richard,

Thanks for the detailed response.

  1. so I think this is the same as described in the book, and is the
    logical behaviour when tracing the execution.

    Here could you tell me which book refered? I usually refered the book (161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide).

  2. Taking the semaphore can unblock the other task that is
    attempting to take the semaphore

I don’t understood this definition. is this applicable for only counting semaphores/generally semaphore? this information and all which location(in book/ freertos forums) available?

3)a ) Created the above issue by creating the semaphore count as 3.
Created the 4 semaphore taking tasks (task1,2,3 and 4) and one semaphore giving task(task5).
While running the code, semaphore gets for all tasks (task1,2,3 and 4).Here each task gets the semaphore until each time slice expires.But here no task get blocked while accessing the semaphore.
The output I get:

Task 1Task 1Task 1
Semaphore given
Semaphore given
Semaphore given
Task 4Task Task 4
Semaphore given
Semaphore given
Semaphore given
Task 3Task 3Task 3
Semaphore given
Semaphore given
Semaphore given
Task 2Task 2Task 2
b) But when changed the semaphore count as 4, semaphore gets only for task1.
Task2,3 and 4 doesn’t get the chance for the semaphore.Not even breakpoints hit at these tasks. In this case also, task 2,3 and 4 gets blocked because of semaphore not available?

  1. If you add a taskYIELD() into each function that is taking the semaphore
    then you can force a context switch while the semaphore is available,
    and therefore allow the other ‘take’ task to obtain it - then they make
    the same number of successful takes each.

Yes, while using the taskYILED(), Each task gets teh semaphore.

rtel wrote on Tuesday, November 19, 2019:

Thanks for the detailed response.

  1. /so I think this is the same as described in the book, and is the
    logical behaviour when tracing the execution./
    Here could you tell me which book refered? I usually refered the book
    (161204_Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide).

Yes - that book.

  1. /If you add a taskYIELD() into each function that is taking the semaphore
    then you can force a context switch while the semaphore is available,
    and therefore allow the other ‘take’ task to obtain it - then they make
    the same number of successful takes each./

Yes, while using the taskYILED(), Each task gets teh semaphore.

Look at the implementation of xQueueReceive() in
FreeRTOS/Source/queue.c, which is the function that actually excutes
when you take a semaphore (semaphores being implemented by queues that
have an item size of zero). You will see that if you call
xQueueReceive() with a block time and there is nothing in the queue (the
semaphore count is zero) the task will block. Now if something is
written to the queue (the semaphore is given, so its count goes up) the
task will unblock - but it won’t run yet because it has the same
priority as the task that gave the semaphore. Now the task that gave
the semaphore loops back around and takes it again - so once again the
queue is empty (semaphore count is zero). Now a tick interrupt occurs
and the task that was unblocked gets to run - but it finds the queue is
empty again (the semaphore count is zero again) so it adjusts its block
time for however long it has already spent in the xQueueReceive()
function and re-enters the blocked state without ever leaving the
xQueueReceive() function…adding a yield forces the task to be able
to run when you know the semaphore is available rather than waiting
until the next tick interrupt when it most likely won’t be available.

sasikalaswathi wrote on Wednesday, November 20, 2019:

Hi Richard,

Detailed response. Thank you so much,