Pergunta

Estou desenvolvendo um Ray Tracer em C ++ usando SDL e Pthread. Estou tendo problemas fazendo meu programa utilizam dois núcleos. Os fios funcionam, mas eles não usam ambos os núcleos a 100%. A interface SDL I write diretamente para sua memória, SDL_Surface.pixels, assim que eu supor que não pode ser SDL me trancar.

As minhas função thread esta aparência:

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);
    }
}

Nota: scene-> renderPixel é const, assim que eu supor ambos os segmentos podem ler a partir da mesma memória. Eu tenho dois segmentos de trabalho fazendo isso, no meu loop principal Eu faço esses trabalhos usando:

//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...

Nota: Eu também tentei criar e juntar os fios em vez de sincronizá-los. Eu compilar isso com "-lpthread -D_POSIX_PTHREAD_SEMANTICS -pthread" e gcc não se queixa.

O meu problema é melhor ilustrado usando um gráfico do uso da CPU durante a execução: uso da CPU durante a execução.
(fonte: jopsen.dk )

Como pode ser visto a partir do gráfico meu programa só usa um núcleo de cada vez, em seguida, alternar entre os dois de vez em quando, mas não conduzir tanto a 100% sempre. O que no mundo que eu fiz de errado? Eu não estou usando qualquer mutex ou semaphors em cena. O que posso fazer para encontrar o bug?

Além disso, se eu colocar while (true) em torno scene-> renderPixel () Eu posso empurrar ambos os núcleos a 100%. Então eu suspeito que isso é causado por sobrecarga, mas eu só sincronizar a cada 0,5 segundo (por exemplo FPS: 0,5), dada uma cena complexa. Sei que pode não ser fácil para me dizer que o meu bug é, mas uma abordagem para depuração este seria grande demais ... Eu não tenho jogado com pthreads antes ...

Além disso, este pode ser um problema de hardware ou kernel, meu kernel é:

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

Nota:

Foi útil?

Solução

Esta é inútil:

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

Se você esperar para esperar por um novo quadro de fazer algo como:

int new_frame = 0;

Primeiro tópico:

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

outro segmento:

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 (), na verdade, liberar o mutex e Unschedule o fio até que a condição é sinalizada. Quando a condição é sinalizada o fio é despertar e a exclusão mútua é levado-re. Tudo isso acontece dentro da função pthread_cond_wait ()

Outras dicas

eu tomar uma facada selvagem no escuro e dizer seus segmentos de trabalho estão gastando muito tempo esperando na variável de condição. Para obter um bom desempenho da CPU neste tipo de situação onde o seu código é principalmente vinculado à CPU, entende-se a usar um estilo orientado tarefa de programação, onde você trata os fios como um "pool" e você usar uma estrutura de fila para o trabalho de alimentação para eles. Eles devem gastar uma quantidade muito pequena de tempo puxando trabalho fora da fila e maior parte de seu tempo fazendo o trabalho real.

O que você tem agora é uma situação onde eles provavelmente estão fazendo o trabalho por um tempo, em seguida, notificar o segmento principal através do semáforo que elas são feitas. O thread principal não vai liberá-los até que ambos os threads têm Término na moldura que está processando atualmente.

Uma vez que você estiver usando C ++, você já pensou em usar Boost.Threads? Faz trabalhando com código multithreaded muito mais fácil, ea API é realmente semelhante ao tipo de pthreads, mas em um "C ++ moderno" espécie de caminho.

Eu não sou nenhum guru pthreads, mas parece-me que o seguinte código está errado:

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

Para citar este artigo

blocos pthread_cond_wait() The Calling rosca até que a condição especificada é sinalizado. Esta rotina deve ser chamado enquanto mutex é bloqueado, e vai liberar automaticamente o mutex enquanto espera. Depois de sinal é recebeu e linha é despertada, mutex será bloqueado automaticamente para uso pelo fio. O programador é então responsável por mutex desbloqueio quando o fio é terminado com ele.

por isso parece-me que você deve liberar o mutex depois o bloco de código follwing o pthread_cond_wait.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top