Проблема с использованием pthread для использования нескольких ядер - PullRequest
1 голос
/ 07 апреля 2009

Я разрабатываю Ray Tracer на C ++, используя SDL и Pthread. У меня проблемы с тем, чтобы моя программа использовала два ядра. Потоки работают, но они не используют оба ядра до 100%. Для интерфейса SDL я пишу непосредственно в его память, SDL_Surface.pixels, поэтому я предполагаю, что это не может быть блокировка SDL.

Моя функция потока выглядит так:

void* renderLines(void* pArg){
while(true){
    //Synchronize
    pthread_mutex_lock(&frame_mutex);
    pthread_cond_wait(&frame_cond, &frame_mutex);
    pthread_mutex_unlock(&frame_mutex);

    renderLinesArgs* arg = (renderLinesArgs*)pArg;
    for(int y = arg->y1; y < arg->y2; y++){
        for(int x = 0; x < arg->width; x++){
            Color C = arg->scene->renderPixel(x, y);
            putPixel(arg->screen, x, y, C);
        }
    }

    sem_post(&frame_rendered);
    }
}

Примечание: scene-> renderPixel является const, поэтому я предполагаю, что оба потока могут читать из одной памяти. У меня есть два рабочих потока, которые делают это, в моем основном цикле я делаю эту работу, используя:

//Signal a new frame
pthread_mutex_lock(&frame_mutex);
pthread_cond_broadcast(&frame_cond);
pthread_mutex_unlock(&frame_mutex);

//Wait for workers to be done
sem_wait(&frame_rendered);
sem_wait(&frame_rendered);

//Unlock SDL surface and flip it...

Примечание: я также пытался создавать и присоединять потоки вместо их синхронизации. Я компилирую это с "-lpthread -D_POSIX_PTHREAD_SEMANTICS -pthread" и gcc не жалуется.

Моя проблема лучше всего проиллюстрирована на графике использования процессора во время выполнения: CPU usage during execution.
(источник: jopsen.dk )

Как видно из графика, моя программа использует только одно ядро ​​за раз, затем время от времени переключается между двумя, но это не приводит к тому, что оба достигают 100%. Что в мире я сделал не так? Я не использую мьютекс или семафор в сцене. Что я могу сделать, чтобы найти ошибку?

Также, если я укажу while (true) вокруг scene-> renderPixel (), я могу увеличить оба ядра до 100%. Так что я подозревал, что это вызвано накладными расходами, но я синхронизирую только каждые 0,5 секунды (например, FPS: 0,5), учитывая сложную сцену. Я понимаю, что мне может быть нелегко сказать, в чем заключается моя ошибка, но подход к отладке тоже был бы хорош ... Я раньше не играл с pthreads ...

Кроме того, это может быть проблема с оборудованием или ядром, мое ядро:

$uname -a
Linux jopsen-laptop 2.6.27-14-generic #1 SMP Fri Mar 13 18:00:20 UTC 2009 i686 GNU/Linux

Примечание:

Ответы [ 3 ]

2 голосов
/ 07 апреля 2009

Это бесполезно:

pthread_mutex_lock(&frame_mutex);
pthread_cond_wait(&frame_cond, &frame_mutex);
pthread_mutex_unlock(&frame_mutex);

если вы ждете, чтобы ждать новый кадр, сделайте что-то вроде:

int new_frame = 0;

Первая тема:

pthread_mutex_lock(&mutex); 
new_frame = 1; 
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

другая тема:

pthread_mutex_lock(&mutex); 
while(new_frame == 0)
  pthread_cond_wait(&cond, &mutex); 
/* Here new_frame != 0, do things with the frame*/
pthread_mutex_unlock(&mutex); 

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

1 голос
/ 07 апреля 2009

Я не гуру pthreads, но мне кажется, что следующий код неправильный:

pthread_mutex_lock(&frame_mutex);
pthread_cond_wait(&frame_cond, &frame_mutex);
pthread_mutex_unlock(&frame_mutex);

Цитировать эту статью

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

так что мне кажется, что вы должны освободить мьютекс после блока кода, следующего за pthread_cond_wait.

1 голос
/ 07 апреля 2009

Я бы сделал дикий удар в темноте и сказал бы, что ваши рабочие потоки тратят много времени на ожидание переменной условия. Чтобы получить хорошую производительность ЦП в такой ситуации, когда ваш код в основном связан с ЦП, подразумевается использование ориентированного на задачи стиля программирования, когда вы рассматриваете потоки как «пул» и используете структуру очереди для передачи работы их. Они должны тратить очень мало времени на то, чтобы вытащить работу из очереди, и большую часть своего времени они выполняют на работе.

То, что у вас сейчас есть, это ситуация, когда они, вероятно, некоторое время выполняют работу, а затем уведомляют главный поток через семафор, что они закончили. Основной поток не освободит их, пока оба потока не закончат работу над кадром, который они обрабатывают в настоящее время.

Поскольку вы используете C ++, рассматривали ли вы вопрос об использовании Boost.Threads? Это значительно облегчает работу с многопоточным кодом, и API фактически похож на pthreads, но в стиле «современного C ++».

...