3

I am creating a threaded application that uses double buffering and I am trying to avoid a potential deadlock. The main idea is that the swap buffer thread locks out the write and the read thread. However the swap buffer thread is fast so the locks will not stay locked long. The Write and Read threads are slower but share time slices efficiently (the goal) because they lock on different mutexes. My question is there a potential deadlock with this design?

  • 3 threads...Thread A, Thread B, and Thread C.
  • 2 mutexes...Front Mutex and the Back Mutex.

  • Thread A fills the back buffer
  • Thread B swaps the buffer.
  • Thread C uses the front buffer.

  • Thread A takes theBackMutex, fills the back buffer, releases theBackMutex.
  • Thread C takes theFrontMutex, uses the front buffer, releases theFrontMutex.
  • Thread B takes theBackMutex, theFrontMutex, swaps the buffers, releases theBackMutex,release theFront Mutex

void *fill_back_buffer() {
    while(1) {
        if (0 != pthread_mutex_lock(&theBackMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1);
        }
        //should we get new data for back buffer?
        pthread_cond_wait(&theBackBufferRefresh, &theBackMutex);
        //fill back buffer
        if (0 != pthread_mutex_unlock(&theBackMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1);
        }
        //hey we done filling the back buffer!
        pthread_cond_signal(&theBackBufferFull);
    }
}


void *swap_buffers() {
    while(1) {
        if (0 != pthread_mutex_lock(&theBackMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1);
        }   
        if (0 != pthread_mutex_lock(&theFrontkMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1);
        }
        //do we have new data in the back buffer?
        pthread_cond_wait(&theBackBufferFull, &theBackMutex);

        //swap buffers
        char* tmp;
        tmp = theBufferAPtr;
        theBufferAPtr = theBufferBPtr;
        theBufferBPtr = tmp;

        if (0 != pthread_mutex_unlock(&theFrontMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1);
        } 
        if (0 != pthread_mutex_unlock(&theBackMutex)) {
            perror("Mutex lock failed (!!):");
            exit(-1); 
        }
        //hey please get more data!
        pthread_cond_signal(&theBackBufferRefresh);
        //hey you can use front buffer now!
        pthread_cond_signal(&theBufferSwapped);

    }
}   

int main(int argc, char *argv[]) {
    //initial fill of the back buffer
    pthread_cond_signal(&theBackBufferRefresh);
    while(1) {
        if (0 != pthread_mutex_lock(&theFrontMutex)) {
                perror("Mutex lock failed (!!):");
                exit(-1);
        } 
        pthread_cond_wait(&theBufferSwapped, &theFrontMutex);
        //use the front buffer and do stuff with it
        if (0 != pthread_mutex_unlock(&theFrontMutex)) {
                perror("Mutex lock failed (!!):");
                exit(-1);
        } 
    }
}
eat_a_lemon
  • 3,158
  • 11
  • 34
  • 50

3 Answers3

2

Condition variables are supposed to be used to signal a change in the state of some (mutex-protected) shared data. You can't use them on their own. Consider what would happen if a thread signals a condition before there is another thread waiting for that condition.

ninjalj
  • 42,493
  • 9
  • 106
  • 148
  • Ah yes I see now. I was using them as signaling only when they are required to signal and wait on a change in state. – eat_a_lemon Mar 25 '11 at 06:21
1

I don't see where you create any threads. I'll assume you create the threads.

swap_buffers() and fill_back_buffer() do contain the classic deadlock implementation. When swap_buffers() is waiting on theBackBufferFull, it has locked theBackMutex. Meanwhile, fill_back_buffer() is waiting on theBackMutex before it sets the signal theBackBufferFull. Therefore, theBackBufferFull will never be signaled, because theBackMutex cannot be released. This is the classic deadlock condition.

Heath Hunnicutt
  • 18,667
  • 3
  • 39
  • 62
  • yea i did not include the entire code example, just enough for the idea. So when 2 threads try to lock the same mutex, that creates a deadlock? I assumed it was smarter and would just block until it eventually jumped out. – eat_a_lemon Mar 15 '11 at 20:29
  • You should read about deadlock. It's not that you have two threads locking the same mutex -- the problem is that you have two threads blocking on the same TWO synchronization primitives, your mutex and your signal, and they do so in reverse order of each other, resulting in deadlock. It is possible to use mutexes without deadlock, but that wasn't your question. Do you have deadlock? Yes, specifically where I described. – Heath Hunnicutt Mar 15 '11 at 20:34
  • It's my understanding that condition variables release their mutex, so I don't see the deadlock you're referring to. – ninjalj Mar 15 '11 at 21:10
  • @ninjalj is correct, `pthrtead_cond_wait()` releases the mutex before waiting on the condition variable. – caf Mar 15 '11 at 21:58
  • Mmm, that's good to learn. Well, my answer is wrong, in that case. – Heath Hunnicutt Mar 15 '11 at 22:26
0

Try to do it without using additional thread for swapping.

samir105
  • 949
  • 11
  • 16