C тупиковая реализация двойного буфера? - PullRequest
3 голосов
/ 15 марта 2011

Я создаю потоковое приложение, использующее двойную буферизацию, и пытаюсь избежать потенциальной тупиковой ситуации. Основная идея заключается в том, что поток буфера подкачки блокирует поток записи и чтения. Однако поток буфера подкачки работает быстро, поэтому блокировки не будут долго оставаться заблокированными. Потоки Write и Read работают медленнее, но эффективно разделяют временные интервалы (цель), потому что они блокируют разные мьютексы. Мой вопрос, есть ли потенциальный тупик с этим дизайном?

  • 3 резьбы ... Резьба A, резьба B и резьба C.
  • 2 мьютекса ... Передний мьютекс и Задний мьютекс.

  • Поток A заполняет задний буфер
  • Поток B меняет буфер.
  • Поток C использует передний буфер.

  • Поток A принимает BackMutex, заполняет задний буфер, освобождает BackMutex.
  • Поток C принимает FrontMutex, использует передний буфер, освобождает FrontMutex.
  • Поток B принимает BackMutex, FrontMutex, меняет местами буферы, освобождает BackMutex, освобождает Front 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);
        } 
    }
}

Ответы [ 3 ]

2 голосов
/ 16 марта 2011

Предполагается, что условные переменные используются для оповещения об изменении состояния некоторых (защищенных мьютексом) общих данных. Вы не можете использовать их самостоятельно. Подумайте, что произойдет, если поток сообщит о состоянии до того, как другой поток ожидает этого условия.

1 голос
/ 15 марта 2011

Я не вижу, где вы создаете какие-либо темы. Я предполагаю, что вы создаете темы.

swap_buffers() и fill_back_buffer() содержат классическую реализацию взаимоблокировки. Когда swap_buffers() ожидает на theBackBufferFull, он заблокировал theBackMutex. Между тем, fill_back_buffer() ожидает на theBackMutex, прежде чем установит сигнал theBackBufferFull. Следовательно, theBackBufferFull никогда не будет сигнализироваться, потому что theBackMutex не может быть освобожден. Это классическое тупиковое состояние.

0 голосов
/ 15 марта 2011

Попробуйте сделать это без использования дополнительной нити для подкачки.

...