Mutex acquired by one task (xSemaphoreTake) can be released (xSemaphoreGive) by another?

I’m trying to implement a Readers–writer lock using using two mutexes and an integer counter as described in:

Concurrent control with “readers” and “writers”
October 1971 Communications of the ACM 14(10):667-668
Pierre-Jacques Courtois
F. Heymans
David Parnas

(See also: https://en.m.wikipedia.org/wiki/Readers–writer_lock .)

The goal is to protect a buffer so that a writer has an exclusive lock, but multiple readers can share a read lock. In this scheme, the “exclusive” (or “global”) lock is acquired by the first reader to enter the critical section and the last reader to leave it. Those can be different tasks. When this happens, I am getting this assert:

assertion "pxTCB == pxCurrentTCB" failed: file "Generated_Source\PSoC6\pdl\rtos\FreeRTOS\10.0.1\Source\tasks.c", line 3910, function: xTaskPriorityDisinherit

The comment before that line says:

		/* A task can only have an inherited priority if it holds the mutex.
		If the mutex is held by a task then it cannot be given from an
		interrupt, and if a mutex is given by the holding task then it must
		be the running state task. */

Is this a limitation of FreeRTOS Semaphores, or do I have a bug somewhere? Is there a better way to implement a Readers–writer lock in FreeRTOS?

A Mutex must be given by the same task that took it. If you need an exclusion device that doesn’t follow that rule you can use a semaphore, so your lock above will need to be a semaphore, not a mutex.

One of the main advantages of the mutex over the semaphore, is that of priority inheritance if a higher priority task want a mutex held by a lower priority task, but that doesn’t really make sense i your case as there may be many tasks that need to get the priority boosts, many who never touched that mutex, so FreeRTOS would have no way to know about the need to boost them.

Thanks. I’ve got it working now simply by changing xSemaphoreCreateMutex() to xSemaphoreCreateBinary(); xSemaphoreGive(). Luckily, all of the tasks involved are at the same priority, so priority inversion should not be an issue. I can see how things could get really messy if that were not the case.