2009-04-07 21 views
1

Je fais un simple ray tracer en C++ en utilisant SDL pour les graphiques et pthread pour le threading. Et j'ai un problème à faire mon programme en utilisant deux cœurs, les threads fonctionnent, ils ne conduisent pas les deux cœurs à 100%. Pour l'interface SDL j'écris directement dans sa mémoire, SDL_Surface.pixels, donc je suppose qu'il ne peut pas être SDL me verrouiller.Problème d'utilisation de pthread pour utiliser plusieurs cœurs

Ma fonction de fil ressemble à ceci:

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

Note: Scène-> renderPixel est const, donc je suppose les deux fils peuvent lire de la même mémoire. J'ai deux threads de travail faisant cela, dans ma boucle principale que je fais ces travaux en utilisant:

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

Note: J'ai aussi essayé de créer et de rejoindre les fils au lieu de les synchroniser. Je compile ceci avec "-lpthread -D_POSIX_PTHREAD_SEMANTICS -pthread" et gcc ne se plaint pas.

Mon problème est le mieux illustré à l'aide d'un graphique de l'utilisation du processeur lors de l'exécution: CPU usage during execution. http://jopsen.dk/downloads/processor_usage.png

Comme on peut le voir sur le graphique de mon programme utilise un seul noyau à la fois, puis de passer entre les deux temps en un moment, mais il ne conduit pas les deux à 100% jamais. Qu'est-ce que j'ai fait de mal dans le monde? Je n'utilise pas de mutex ou de sémaphores dans la scène. Que puis-je faire pour trouver le bogue?

Aussi, si je mets while (true) autour de scene-> renderPixel() je peux pousser les deux cœurs à 100%. J'ai donc soupçonné que cela est dû à des frais généraux, mais je ne fais que synchroniser toutes les 0,5 secondes (par exemple, FPS: 0,5), étant donné une scène complexe. Je me rends compte qu'il ne serait pas facile de me dire ce qu'est mon bogue, mais une approche pour le déboguer serait bien aussi ... Je n'ai pas joué avec des pthreads avant ...

Aussi, cela peut-il être un problème matériel ou du noyau, mon noyau est:

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

note:

Répondre

2

Ceci est inutile:

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

si vous attendez d'attendre un nouveau cadre faire quelque chose comme:

int new_frame = 0;

fil Première:

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

autre thread:

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(), libérer réellement le mutex et déprogrammer le fil jusqu'à ce que la condition est signalée. Lorsque la condition est signalée, le thread est réveillé et le mutex est repris. Tout cela se produit dans la fonction

+0

Cela a aidé pthread_cond_wait(), aussi j'ai découvert que le rendu chaque seconde ligne au lieu de la moitié de l'image fait les deux fils rendent dans presque en même temps ... Je ne finalement réussi à conduire à la fois core à 100%, mais il n'a pas amélioré mon frame rate :) - Ou je suis juste mesure mal ... Merci pour l'aide ... – jonasfj

+0

Haha, la première étape « d'optimisation » est toujours essayer de faire l'algorithme parallèle aussi efficace avec n processeurs, que le séquentiel était avec un seul processeur. Continuez à essayer, vous obtiendrez éventuellement une amélioration – Ben

1

Je prendrais un coup de poignard sauvage dans l'obscurité et que votre fils de travailleurs passent beaucoup de temps d'attente sur la variable de condition. Pour obtenir de bonnes performances CPU dans ce type de situation où votre code est principalement lié au processeur, il est entendu que vous utilisez un style de programmation orienté tâches, où vous traitez les threads comme un pool et utilisez une structure de file d'attente pour alimenter le travail. leur. Ils devraient passer une très petite quantité de temps à retirer du travail de la file d'attente et à passer le plus clair de leur temps à faire le travail. Ce que vous avez en ce moment est une situation où ils travaillent probablement pendant un certain temps, puis notifier le thread principal par le sémaphore qu'ils ont fait. Le thread principal ne les relâchera pas tant que les deux threads n'auront pas fini de travailler sur le frame qu'ils sont en train de traiter.

Puisque vous utilisez C++, avez-vous envisagé d'utiliser Boost.Threads? Cela rend le travail avec du code multithread beaucoup plus facile, et l'API est en quelque sorte similaire à pthreads, mais d'une manière "C++ moderne".

1

Je ne suis pas gourou pthreads, mais il me semble que le code suivant est erroné:

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

Pour citer this article

pthread_cond_wait() bloque l'appel de fil jusqu'à ce que la condition spécifiée est signalé. Cette routine doit être appelé pendant que mutex est verrouillé, et il libérera automatiquement le mutex pendant qu'il attend. Après que le signal est reçu et le fil est réveillé, mutex sera automatiquement verrouillé pour une utilisation par le fil. Le programmeur est alors responsable du déverrouillage du mutex lorsque le fil est fini avec lui.

il me semble que vous devriez délier la mutex après le bloc de code follwing le pthread_cond_wait.