Readers/Writer Lock

jeronimo479 wrote on Tuesday, May 29, 2018:

Example for a Readers/Writer Lock:

struct ReadWriteLock_struct
{
    SemaphoreHandle_t xSem;
    SemaphoreHandle_t xMutex;
    uint32_t max_readers;
} ReadWriteLock;

typedef struct ReadWriteLock_struct *ReadWriteLock_t;

ReadWriteLock_t rwlock;

void RWLock_readers_take(ReadWriteLock_t rwlock)
{
    xSemaphoreTake(rwlock->xSem, portMAX_DELAY);
}

void RWLock_readers_give(ReadWriteLock_t rwlock)
{
    xSemaphoreGive(rwlock->xSem);
}

void RWLock_writer_take(ReadWriteLock_t rwlock)
{
    uint_fast8_t count;

    xSemaphoreTake(rwlock->xMutex, portMAX_DELAY);
    for(count = 0; count < rwlock->max_readers; count++)
        xSemaphoreTake(rwlock->xSem,  portMAX_DELAY);
}

void RWLock_writer_give(ReadWriteLock_t rwlock)
{
    uint_fast8_t count;
    for (count=0; count < rwlock->max_readers; count++)
        xSemaphoreGive(rwlock->xSem);
    xSemaphoreGive(rwlock->xMutex);
}


void main(void)
{
    rwlock = (ReadWriteLock_t)pvPortMalloc(sizeof(struct ReadWriteLock_struct));
    rwlock->xSem = xSemaphoreCreateCounting(4);
    rwlock->xMutex = xSemaphoreCreateMutex();
    
    ...
    
    vPortFree(rwlock->xMutex);
    vPortFree(rwlock->xSem);
    vPortFree(rwlock);
} 

Previously I posted this because I thought I had trouble with a recursive xSemaphoreTake() call. I was mistaken. I had grouped the components into a struct, then only allocated the size of a pointer, not the size of the struct to rwlock:

—BAD CODE—> rwlock = (ReadWriteLock_t)pvPortMalloc(sizeof(ReadWriteLock_t))

So the problem wasn’t with repeated calls to xSemaphoreTake(), but with the improper allocation or rwlock.

I hope this helps others.

Wayne

rtel wrote on Wednesday, May 30, 2018:

Thanks for reporting back. A semaphore can be used recursively if it is
created with xSemaphoreCreateRecursiveMutex().

jeronimo479 wrote on Wednesday, May 30, 2018:

xSemaphoreCreateRecursiveMutex() doesn’t allow me to establish a maximum count or an initial count. It is also documented as for use with mutex, not semaphore. My implementation specifically wanted N-tasks to be able to read from one resource, and have one task take all the semaphores before writing. So I don’t think xSemaphoreCreateRecursiveMutex() is the right choice.