What happens if a Task tries to take a semaphore it has already obtained

What happens if a Task tries to take a binary semaphore ( with xSemaphoreTake() ) it has already obtained? Will it enter the blocked state and not be able to give the sempahore back again (deadlock)?

Yes. Mutexes instead can be used resursively FreeRTOS Recursive Mutexes if needed.

Yes, as it will block itself?

Yes, it blocks and waits for the semaphore being signaled.

Be careful, Benjamin: Semaphores - unlike Muteces - are not associated with ownership; thus the task does neither block itself nor deadlock; it is well possible (and desired behavior) for another task to signal the semaphore and thus wake up the suspended task, as Hartmut suggested.

A task can only deadlock itself if it owns a non-recursive mutex and attempts to claim it again as the only task that can resolve the block is that task. Compound deadlocks must span over several tasks.

I tried putting two xSemaphoreTake() statements after eachother and the task got blocked for ever after the second statement

How do you create the object that the task waits on?

If it’s a non recursive mutex, then yes, the task has deadlocked itself, and you need to switch to a recursive mutex to prevent that from happening (of course you must release the mutex as many times as you claimed it then to make it available for other tasks).

If it’s a semaphore whose count is exeeded by the first call, then your task is NOT deadlocked because it is possible for other tasks to release (signal) the semaphore. That’s a very important difference.

It’s a little bit unfortunate that FreeRTOS uses the same API set for using semaphores and muteces as that obfuscates the difference.

it’s a function call to xSemaphoreTake(), but that is a define, which calls xQueueGenericReceive().
The SW platform I’m working on uses FreeRTOS but I don’t know if it is original FreeRTOS source code or modified FreeRTOS code. I know they have modified some of the API functions.

Hi Benjamin,

I did not ask for the code that takes, but for the code that creates the synchronization object. In other words, do you create a mutex or a semaphore?

Going back to the original question, here is a tip for being able to find out the answer. The FreeRTOS download contains Windows, Linux and QEMU ports which are easy to debug. You can use one of those to add something simple, such as:

SemaphoreHandle_t xSemaphore;
BaseType_t xReturn;

	xSemaphore = xSemaphoreCreateBinary();

	/* Make sure the semaphore is available. */
	xSemaphoreGive( xSemaphore );

	/* Now try taking the semaphore twice - you can step through the code to
	see what happens. */
	xReturn = xSemaphoreTake( xSemaphore, portMAX_DELAY );
	( void ) xReturn; /* Stop xReturn being optimised away. */
	xReturn = xSemaphoreTake( xSemaphore, portMAX_DELAY );
	configASSERT( xReturn );

Then you can compile and step through the code line by line to see exactly how it works, and what the behaviour is.

1 Like

ok, I’m sorry for having failed to notice the explicit remark in your first post about the object being a binary semaphore.

But anyways, what I wrote earlier still holds: The task that does the claim twice is not necessarily deadlocked. As long as other tasks that have access to the object can release the semaphore, your task has a chance to resume. Unless, of course, your task has in between the two claims taken another sync object that the other task to signal the semaphore needs to obtain before releasing “your” semaphore. It is circular dependencies like that that define a deadlock.

Sounds like splitting hairs in two, but those subtle distinctions make all the difference in concurrent programming.

Yes I’ve tried that, and the task that calls xSemaphoreTake() gets blocked/deadlocked after the second call to xSemaphoreTake().

So I now know the answer :slight_smile:
Thanks for your reply!

Yes it’s a binary semaphore, created with vSemaphoreCreateBinary().

And it will deadlock if the task call it twice.

Thanks for your input!

It’s quite an easy fix to prevent deadlock though. Before taking the sempahore, just need a if-condition to see if the task that wants to take the semaphore have not taken it already, for example with xTaskGetCurrentTaskHandle()

No, it will NOT deadlock. I tried to explain that several times. You might want to look up the definition of deadlock. A deadlock is a condition that can not be resolved. With a binary semaphore, it can be resolved from outside, meaning another task can resolve the situation by signalling the semaphore.

The issue here is that for historical reason, most people use the term semaphore when in 95% of the cases they refer to muteces. Those are different concepts.

Anyways, keep using the term deadlock if you want to, but it’s wrong in this context, and that’s not merely a theoretical discussion.

This won’t work well @Benj. Almost certain you’ll stumble into race condition issues.
Which problem do you wan’t to solve ?

Ok, deadlock or not, but the task was blocked (for ever)

To not blocking the task for ever if it accedently tries to take the semaphore twice

Can’t you just ensure by your code that this never happens ? How do you come into the situation taking a binary semaphore twice ? What’s the purpose of this binary semaphore ? Usually a (binary) semaphore is just signaled to wake up a task. That’s it.

It’s used to protect a resource, that two different tasks wants to take.