Question

I have two threads, using C pthreads on linux. One of them writes data and the other is reading it. I'm using a variable to allow the read thread when is allowed to read and the write one when is allowed. So the mutex applies to this boolean variable called "newData". My question is: do I need to lock/unlock the mutex around the accesses inside the "if" condition? Both ways work, but I think just because the chances of overlapping a write/read over a this variable are very few. I show both alternatives to explain better my question:

Thread 1:

pthread_mutex_lock( &lattice_mutex );
if (!newData) {
    pthread_mutex_unlock( &lattice_mutex );
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

Thread 2:

pthread_mutex_lock( &lattice_mutex );
if(newData) {
    pthread_mutex_unlock( &lattice_mutex );
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

Second version, which works but I don't know if it is correct:

Thread 1:

if (!newData) {
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
}

Thread 2:

if(newData) {
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
}
Was it helpful?

Solution

This is derived from your first version - it is somewhat simpler.

Thread 1: writer

pthread_mutex_lock(&lattice_mutex);
if (!newData) {
    pthread_mutex_unlock(&lattice_mutex);  // Omit?
    uchar *lattice_pos = lattice;
    int i;
    for (i = 0; i < size; i++)
        *lattice_pos++ = rand() % CHAR_MAX;
    pthread_mutex_lock(&lattice_mutex);   // Omit?
    newData = TRUE;
}
pthread_mutex_unlock(&lattice_mutex);

Thread 2: reader

pthread_mutex_lock(&lattice_mutex);
if (newData) {
    pthread_mutex_unlock(&lattice_mutex);   // Omit?
    renderUpdate();
    pthread_mutex_lock(&lattice_mutex);     // Omit?
    newData = FALSE;
}
pthread_mutex_unlock(&lattice_mutex);

It depends on exactly how the lattice information is meant to be used, but given the name of the mutex, I think you should keep it locked while you are modifying the lattice, hence the two pairs of lines marked 'Omit?' should be removed. Otherwise, the lattice is not protected from concurrent access.

Added: I think the second version is erroneous - it doesn't properly protect the lattice.

OTHER TIPS

The first version is correct, you need the mutex on both writes and reads.

However, AFAIK, almost all architectures out there have simple read and write accesses to one unit of data (eg. int) atomic. However, note that on architectures with weak memory ordering, you might have issues like seeing the "buffer-full" flag to true before the buffer actually contains the data.

Note that the code is probably not the best you can do, because it never sleeps (uses busy waiting). If you wanted to wait for the data in either thread, you would have to use a condition variable with the mutex.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top