Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C double buffer implementation deadlock?

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);
        } 
    }
}
like image 647
eat_a_lemon Avatar asked Mar 24 '26 20:03

eat_a_lemon


2 Answers

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.

like image 183
ninjalj Avatar answered Mar 27 '26 10:03

ninjalj


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.

like image 45
Heath Hunnicutt Avatar answered Mar 27 '26 11:03

Heath Hunnicutt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!