cmultithreadingpthreadsreaderwriterlock

When to wake up writer in reader-writer problem? before releasing mutex or after?


I wonder what is the best practice in my situation. in the following code i signal the writer before unlocking the mutex

void* Reader(void *context)
{
    while(TRUE)
    {
        LOCK(&g_mutex);
        ++g_activeReaders;
        UNLOCK(&g_mutex);

        printf("reader: %ld counter val: %d ", (long)context, g_counter);

        LOCK(&g_mutex);
        --g_activeReaders;
        printf("g_activeReaders: %d \n", g_activeReaders);
        if(0 == g_activeReaders)
        {
            SIGNAL(&g_cv);
        }
        UNLOCK(&g_mutex);
    }

    return NULL;
}

I wonder if this is better for some reason, to prevent deadlock

void* Reader(void *context)
{
    int signalFlag;
        while(TRUE)
    {
                signalFlag = 0;
        LOCK(&g_mutex);
        ++g_activeReaders;
        UNLOCK(&g_mutex);

        printf("reader: %ld counter val: %d ", (long)context, g_counter);

        LOCK(&g_mutex);
        --g_activeReaders;
        printf("g_activeReaders: %d \n", g_activeReaders);
        if(0 == g_activeReaders)
        {
                        signalFlag = 1;
        }
        UNLOCK(&g_mutex);

                if(signalFlag)
                SIGNAL(&g_cv);
    }


    return NULL;
}

my complete program is:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_cv = PTHREAD_COND_INITIALIZER;
int g_activeReaders = 0;
int g_counter;

#define LOCK(X) pthread_mutex_lock(X)
#define UNLOCK(X) pthread_mutex_unlock(X)
#define WAIT pthread_cond_wait
#define WAKE_ALL pthread_cond_broadcast
#define SIGNAL pthread_cond_signal
#define JOIN pthread_join
#define TRUE 1
#define N 3

void* Writer(void * context)
{
    while(TRUE)
    {
        LOCK(&g_mutex);
        while(g_activeReaders)
        {
            WAIT(&g_cv, &g_mutex);
        }

        ++g_counter;
        UNLOCK(&g_mutex);
    }

    return NULL;
}

void* Reader(void *context)
{
    while(TRUE)
    {
        LOCK(&g_mutex);
        ++g_activeReaders;
        UNLOCK(&g_mutex);

        printf("reader: %ld counter val: %d ", (long)context, g_counter);

        LOCK(&g_mutex);
        --g_activeReaders;
        printf("g_activeReaders: %d \n", g_activeReaders);
        if(0 == g_activeReaders)
        {
            SIGNAL(&g_cv);
        }
        UNLOCK(&g_mutex);
    }

    return NULL;
}

void InitWriters(pthread_t* writers, int count)
{
    int status;
    int i;

    for(i = 0; i < count; ++i)
    {
        status = pthread_create(&writers[i], NULL, Writer, NULL);

        if(status)
        {
            fprintf(stderr, "Writer create fail\n");
            exit(-1);
        }
    }
}

void InitReaders(pthread_t* readers, int count)
{
    int status;
    int i;

    for(i = 0; i < count; ++i)
    {
        long e = i;
        status = pthread_create(&readers[i], NULL, Reader, (void*) e);

        if(status)
        {
            fprintf(stderr, "readers create fail\n");
            exit(-1);
        }
    }
}

void JoinThreads(pthread_t* threads, int count)
{
    int status;
    int i;

    for(i = 0; i < count; ++i)
    {
        status = pthread_join(threads[i], NULL);

        if(status)
        {
            fprintf(stderr, "readers create fail\n");
            exit(-1);
        }
    }
}

int main(void)
{
    pthread_t writer;
    pthread_t readers[N];

    InitWriters(&writer, 1);
    InitReaders(readers, N);

    JoinThreads(&writer, 1);
    JoinThreads(readers, N);

    pthread_cond_destroy(&g_cv);
    pthread_mutex_destroy(&g_mutex);

    return 0;
}

my implementation is based upon pseudo code found (here)[Reader/Writer implementation in C


Solution

  • It does not matter for correctness - either is fine, and there is no deadlock.

    In the case where you are using different thread priorities, the implementation where the condition variable is signalled before unlocking the mutex can ensure that a higher-priority thread that is waiting on the condition variable will get the mutex in preference to a lower-priority thread that is just waiting on the mutex.