2009-04-07 3 views
1

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

Моя функция потока выглядит следующим образом:

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 является сопзЬ, поэтому я предполагаю, что оба потока могут читать из одной и той же памяти. У меня есть два рабочих потоков делают это, в моем главном цикле я делаю эти работы с помощью:

//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. http://jopsen.dk/downloads/processor_usage.png

Как видно из графика, моя программа использует только одно ядро, в то время, а затем переключаться между ними каждый раз в в то время как, но это не приводит к тому, что на 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 

Примечание:

ответ

2

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

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()

+0

Это помогло, также я обнаружил, что рендеринг каждой второй строки вместо половины изображения сделал два потока рендерингом почти в одно и то же время ... Поэтому мне в итоге удалось управлять обоими ядро до 100%, но это не улучшило мою частоту кадров :) - Или я просто измеряю это неправильно ... Спасибо за помощь ... – jonasfj

+0

Ха-ха, первый шаг «оптимизации» всегда пытается сделать параллельный алгоритм, эффективный с n процессорами, чем последовательный с одним процессором. Продолжайте пытаться, вы в конечном итоге получите улучшение – Ben

1

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

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

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

1

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

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

Чтобы процитировать this article

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

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

Смежные вопросы