Domanda

sto sviluppando un Ray Tracer in C ++ usando SDL e Pthread. Sto avendo problemi rendendo il mio programma utilizza due core. I fili funzionano, ma non usano entrambi i core al 100%. Per interfacciare SDL scrivo direttamente alla sua memoria, SDL_Surface.pixels, quindi immagino che non può essere SDL mi blocco.

La mia funzione filo simile a questa:

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, quindi assumere entrambi i fili possono leggere dalla memoria stessa. Ho due thread di lavoro a fare questo, nel mio ciclo principale faccio questi lavori utilizzando:

//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: Ho anche cercato di creare e unendo i fili invece di sincronizzazione. Compilo questo con "-lpthread -D_POSIX_PTHREAD_SEMANTICS -pthread" e gcc non si lamenta.

Il mio problema è meglio illustrato con un grafico di utilizzo della CPU durante l'esecuzione: utilizzo della CPU durante l'esecuzione.
(fonte: jopsen.dk )

Come si può vedere dal grafico mio programma usa solo core alla volta, quindi il passaggio tra i due ogni tanto, ma non guidare sia al 100% mai. Ciò che nel mondo ho fatto di sbagliato? Non sto usando qualsiasi mutex o semaphors in scena. Cosa posso fare per trovare il bug?

Anche se ho messo while (true) intorno scene-> renderPixel () posso spingere entrambi i core al 100%. Così ho il sospetto che questo è causato da sovraccarico, ma la sincronizzazione solo ogni 0,5 secondi (per esempio FPS: 0,5), data una scena complessa. Mi rendo conto che potrebbe non essere facile per me dire che cosa il mio errore è, ma un approccio al debug questo sarebbe troppo grande ... non ho giocato con pthreads prima ...

Inoltre, questo può essere un problema hardware o kernel, il 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:

È stato utile?

Soluzione

Questa è inutile:

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

se si aspetta di aspettare un nuovo telaio fare qualcosa di simile:

int new_frame = 0;

Per prima discussione:

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

altro 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 (), in realtà rilasciare il mutex, e non programmata il filo finché viene segnalata la condizione. Quando la condizione viene segnalata il filo viene svegliato e il mutex è ri-presa. Tutto questo accada all'interno della funzione pthread_cond_wait ()

Altri suggerimenti

mi piacerebbe prendere una pugnalata selvaggio nel buio e dire i vostri thread di lavoro stanno spendendo un sacco di tempo in attesa sulla variabile di condizione. Per ottenere buone prestazioni della CPU in questo tipo di situazione in cui il codice è in gran parte della CPU bound, si intende utilizzare uno stile compito orientata di programmazione, in cui si trattano i fili come un "pool" e si utilizza una struttura di coda per alimentare il lavoro di loro. Essi dovrebbero spendere una piccola quantità di tempo tirare il lavoro dalla coda e la maggior parte del loro tempo a fare il lavoro effettivo.

Quello che hai in questo momento è una situazione in cui sono probabilmente facendo il lavoro per un po ', poi notificare il thread principale tramite il semaforo che hanno finito. Il filo principale non rilascerà finché entrambi i fili hanno terminato di lavorare sul telaio che in corso di elaborazione.

Dal momento che si sta utilizzando C ++, hai pensato di utilizzare Boost.Threads? Si rende il lavoro con il codice multithread molto più facile, e l'API è in realtà sorta di simile a pthreads, ma in un "moderno C ++" tipo di strada.

Non sono un guru pthreads, ma mi sembra che il seguente codice è errato:

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

Per citare questo articolo

  

blocchi pthread_cond_wait() The Calling   infilare finché la condizione specificata   viene segnalato. Questa routine dovrebbe essere   chiamato mentre mutex è bloccato, ed è   rilascerà automaticamente il mutex   durante l'attesa. Dopo il segnale è   ricevuto e filo è risvegliato, mutex   si blocca automaticamente per l'uso   dal filo. Il programmatore è quindi   responsabile per sbloccare mutex quando   il filo è finito con esso.

così sembra a me che si dovrebbe essere rilasciando il mutex dopo il blocco di codice follwing del pthread_cond_wait.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top